How to avoid double slash

If your link points to a folder it should ends with a slash (/), but if you use a php variable to define it and you sometimes need to add some page at the end of your link, you could have a problem: the double slash (//).
I.g. you could have this variable php

$mypath="mypath1/mypath2/";

The final slash is recommended to avoid a redirect (that you would have with $mypath="mypath1/mypath2).
And you can call that variable in all your webpages pointing at that folder, in this way:

<a href=”<?php echo $mypath ?>”>some name</a>

But if you have to point to a specific page in that folder, you shouldn’t use this code:

<a href="<?php echo "$mypath/a-specific-page.php" ?>">some other name</a>

otherwise you will get, in the final html, a double slash. No way, course to write $mypatha-specific-page.php , because in this case your would call a not existing variable ($mypatha-specific-page.php ).

A good solution could then be this

<a href="<?php echo $mypath . 'a-specific-page.php' ?>">some other name</a>


esport and show FF bookmarks in a webpage

With the help of IA I managed to get Firefox bookmarks

import os
import json
import sqlite3
import shutil
import tempfile

profile_name = "your-profile"  # <-- cambia con il tuo
profile_path = os.path.expanduser(f"~/.mozilla/firefox/{profile_name}")
db_path = os.path.join(profile_path, "places.sqlite")

if not os.path.isfile(db_path):
    print(f"Il file places.sqlite non esiste: {db_path}")
    exit(1)

# Copia temporanea per evitare blocchi
tmp_dir = tempfile.gettempdir()
temp_db_path = os.path.join(tmp_dir, "places_copy.sqlite")
shutil.copy2(db_path, temp_db_path)

conn = sqlite3.connect(temp_db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()

# Preleva tutte le informazioni rilevanti
query = """
SELECT
    b.id,
    b.title,
    b.parent,
    b.type,
    b.fk,
    b.dateAdded,
    p.url,
    ia.content AS description
FROM moz_bookmarks b
LEFT JOIN moz_places p ON b.fk = p.id
LEFT JOIN moz_items_annos ia ON b.id = ia.item_id
LEFT JOIN moz_anno_attributes a_attr ON ia.anno_attribute_id = a_attr.id
WHERE (b.type = 1 OR b.type = 2)
  AND (a_attr.name IS NULL OR a_attr.name = 'bookmarkProperties/description')
ORDER BY b.parent, b.position
"""

cursor.execute(query)
rows = cursor.fetchall()

# Costruisci dizionario gerarchico
items = {row["id"]: {
    "id": row["id"],
    "title": row["title"] if row["title"] else "(senza titolo)",
    "type": "folder" if row["type"] == 2 else "bookmark",
    "url": row["url"] if row["type"] == 1 else None,
    "description": row["description"],
    "children": []
} for row in rows}

# Organizza gerarchia
root = []
for row in rows:
    item = items[row["id"]]
    parent_id = row["parent"]
    if parent_id in items:
        items[parent_id]["children"].append(item)
    else:
        root.append(item)

# Salva in JSON
with open("bookmarks_full.json", "w", encoding="utf-8") as f:
    json.dump(root, f, ensure_ascii=False, indent=2)

print(f"Esportazione completata: {len(root)} cartelle o elementi di primo livello.")
conn.close()
os.remove(temp_db_path)

also selecting a specific bookmark folder

import os
import sqlite3
import shutil
import tempfile
import sys

profile_name = "your-FF-profile"
folder_name_to_export = "[the folder name]"  # Nome della cartella da esportare
output_path = "bookmarks-FF-[a name].php"

# Percorso del profilo
profile_path = os.path.expanduser(f"~/.mozilla/firefox/{profile_name}")
db_path = os.path.join(profile_path, "places.sqlite")

if not os.path.isfile(db_path):
    print(f"Il file places.sqlite non esiste: {db_path}")
    sys.exit(1)

# Copia temporanea del DB
tmp_dir = tempfile.gettempdir()
temp_db_path = os.path.join(tmp_dir, "places_copy.sqlite")
shutil.copy2(db_path, temp_db_path)

conn = sqlite3.connect(temp_db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()

# 1. Query per cartelle e segnalibri (senza tag)
query = """
SELECT
  b.id,
  b.title,
  b.parent,
  b.type,
  b.fk,
  p.url
FROM moz_bookmarks b
LEFT JOIN moz_places p ON b.fk = p.id
WHERE b.type IN (1, 2)
ORDER BY b.parent, b.position
"""

cursor.execute(query)
rows = cursor.fetchall()

# Costruzione struttura
items = {row["id"]: {
    "id": row["id"],
    "title": row["title"] or "(senza titolo)",
    "type": "folder" if row["type"] == 2 else "bookmark",
    "url": row["url"] if row["type"] == 1 else None,
    "description": None,
    "children": []
} for row in rows}

# Costruzione gerarchia
for row in rows:
    item = items[row["id"]]
    parent_id = row["parent"]
    if parent_id in items:
        items[parent_id]["children"].append(item)

# 2. Query per associare tag reali ai segnalibri
tag_query = """
SELECT
  b.id AS bookmark_id,
  GROUP_CONCAT(tg.title, ', ') AS tags
FROM moz_bookmarks b
LEFT JOIN moz_bookmarks bt ON bt.fk = b.fk
LEFT JOIN moz_bookmarks tg ON tg.id = bt.parent AND tg.parent = -3
WHERE b.type = 1
GROUP BY b.id
"""

cursor.execute(tag_query)
tag_rows = cursor.fetchall()

# Assegna i tag ai segnalibri nella struttura
for row in tag_rows:
    bookmark_id = row["bookmark_id"]
    tags = row["tags"]
    if bookmark_id in items:
        items[bookmark_id]["description"] = tags if tags else "(senza tag)"

# Cerca la cartella da esportare
matching_folders = [item for item in items.values()
                    if item["type"] == "folder" and item["title"] == folder_name_to_export]

if not matching_folders:
    print(f"Nessuna cartella trovata con nome '{folder_name_to_export}'.")
    conn.close()
    os.remove(temp_db_path)
    sys.exit(1)

# Funzione per scrivere array PHP
def to_php_array(item, indent=2):
    space = ' ' * indent
    lines = [f"{space}["]
    lines.append(f"{space}  'title' => '{item['title'].replace('\'', '\\\'')}',")
    if item.get("url"):
        lines.append(f"{space}  'url' => '{item['url'].replace('\'', '\\\'')}',")
    if item.get("description"):
        lines.append(f"{space}  'description' => '{item['description'].replace('\'', '\\\'')}',")
    if item.get("children"):
        lines.append(f"{space}  'children' => [")
        for child in item["children"]:
            lines.append(to_php_array(child, indent + 4) + ",")
        lines.append(f"{space}  ],")
    lines.append(f"{space}]")
    return "\n".join(lines)

# Scrittura file PHP
with open(output_path, "w", encoding="utf-8") as f:
    f.write("<?php\nreturn [\n")
    for folder in matching_folders:
        f.write(to_php_array(folder, indent=2))
        f.write(",\n")
    f.write("];\n")

print(f"Esportazione completata in {output_path}")

conn.close()
os.remove(temp_db_path)

and output them in a php webpage

<?php
$segnalibri = include 'bookmarks-FF-[a name].php';

function stampaSegnalibri($items) {
    foreach ($items as $item) {
        echo "<div style='margin-bottom:8px'>";

        if (isset($item['url'])) {
            // titolo come link
            $title_html = htmlspecialchars($item['title'], ENT_QUOTES);
            $url_html = htmlspecialchars($item['url'], ENT_QUOTES);
            echo "<a href=\"$url_html\" target=\"_blank\">$title_html</a>";
        } else {
            // solo titolo testo normale
            echo "<strong>" . htmlspecialchars($item['title'], ENT_QUOTES) . "</strong>";
        }

        // descrizione (se presente)
        if (!empty($item['description'])) {
            $desc_html = htmlspecialchars($item['description'], ENT_QUOTES);
            echo "<br><small style='color: #555;'>$desc_html</small>";
        }

        // figli (ricorsivo)
        if (isset($item['children']) && count($item['children']) > 0) {
            echo "<div style='margin-left:20px; margin-top:4px;'>";
            stampaSegnalibri($item['children']);
            echo "</div>";
        }

        echo "</div>";
    }
}

stampaSegnalibri($segnalibri);
?>

The problem is that FF doesn’t have a description field, and I didn’t manage tgo get it from another filed, such as ‘tags’ one.

automatize your website

Recently I managed to make some new improvements about website automation

After the automation of gallery, in a previous post, I did this other automation (with php):

list php pages with a given name

With the following code, you can list (and link) all webages php files containing in its filename the variable you can set:

<?php
echo "<h3>testi on-line di $autore</h3>";
echo "<ul class=\"flexmenu\">\n";

// Escape special characters in $autore to use safely in glob pattern
$phpfiles = glob("$path/*" . preg_quote($autore_di, '/') . "*.php"); // Get all PHP files with $autore in the name

foreach ($phpfiles as $phpfile) {
    $contents = file_get_contents($phpfile);

    preg_match('/\$title\s*=\s*"(.*?)";/', $contents, $titleMatch);
    preg_match('/\$subtitle\s*=\s*"(.*?)";/', $contents, $subtitleMatch);
    preg_match('/\$description\s*=\s*"(.*?)";/', $contents, $descriptionMatch);
    preg_match('/\$order\s*=\s*"(.*?)";/', $contents, $orderMatch);

    $title = $titleMatch[1] ?? 'No title';
    $subtitle = $subtitleMatch[1] ?? 'No subtitle';
    $order = $orderMatch[1] ?? '';
    $description = $descriptionMatch[1] ?? 'No description';

    // Correctly extract the filename
    $filename = $phpfile; // Use basename on $phpfile directly

    echo " <li role='menuitem' style=\"order:$order\"><a href=\"{$filename}\">{$title}</a>, <i>{$subtitle}</i>: {$description}</li>\n";
}

echo "</ul>";


echo "<h3>testi on-line su $autore</h3>";
echo "<ul class=\"flexmenu\">\n";

// Escape special characters in $autore to use safely in glob pattern
$phpfiles = glob("$path/*" . preg_quote($autore_su, '/') . "*.php"); // Get all PHP files with $autore in the name

foreach ($phpfiles as $phpfile) {
    $contents = file_get_contents($phpfile);

    preg_match('/\$title\s*=\s*"(.*?)";/', $contents, $titleMatch);
    preg_match('/\$subtitle\s*=\s*"(.*?)";/', $contents, $subtitleMatch);
    preg_match('/\$description\s*=\s*"(.*?)";/', $contents, $descriptionMatch);
    preg_match('/\$order\s*=\s*"(.*?)";/', $contents, $orderMatch);

    $title = $titleMatch[1] ?? 'No title';
    $subtitle = $subtitleMatch[1] ?? 'No subtitle';
    $order = $orderMatch[1] ?? '';
    $description = $descriptionMatch[1] ?? 'No description';

    // Correctly extract the filename
    $filename = $phpfile; // Use basename on $phpfile directly

    echo " <li role='menuitem' style=\"order:$order\"><a href=\"{$filename}\">{$title}</a>, <i>{$subtitle}</i>: {$description}</li>\n";
}

echo "</ul>";
?>

You can call that code in a webpage, with something like this:

<?php
/*files beginning with i must be uppercase */
$path="../testi";// your path
$autore="Aristotele";
$autore_di="Aristotele[di]";//texts of $autore
$autore_su="Aristotele[su]";//texts about $autore
include "$root/lista-files-testi-[autore]-online-con-metatags.inc";
?>

automatically list files in a website menu

You can create an automatic menu list of your files in a given folder, and in a folder with the same name of one file (without extension, of course). With a code like the following:

<?php
$phpfiles = glob("{$root}/$menupath/[^index]*.php");

foreach ($phpfiles as $phpfile) {
  $contents = file_get_contents($phpfile);

  // Match $order
  preg_match('/\$order\s*=\s*"(.*?)";/', $contents, $orderMatches);

  // Match $title
  preg_match('/\$title\s*=\s*"(.*?)";/', $contents, $titleMatches);

  // Assign the values
  $order = $orderMatches[1] ?? null;
  $title1 = $titleMatches[1] ?? null;

  $filename1 = basename($phpfile); // Get only the file name
  $filename = pathinfo($phpfile, PATHINFO_FILENAME);
  $filename = str_replace('-', ' ', $filename); // Replace hyphens with spaces in the filename
  $filename = ucfirst($filename); // Optional: Capitalize the first letter for better readability
  $link = "$root/$menupath/{$filename1}"; // Create the relative link

  // Start the list item for the menu
  echo "<li role='menuitem' style=\"order:$order\"><a href=\"{$link}\">{$title1}</a>";

  // Check if a sub-menu is required (look for a folder matching the filename)
  $folder = "{$root}/$menupath/{$filename}";
  if (is_dir($folder)) {
    // If the subfolder exists, generate the sublist automatically
    $subfiles = glob("{$folder}/[^index]*.php");
    if (count($subfiles) > 0) {
      echo "<ul class='flexmenu'>"; // Start sublist
      foreach ($subfiles as $subfile) {
        $subfileName = basename($subfile);
        $subfileTitle = pathinfo($subfile, PATHINFO_FILENAME);

        // Match $order for subfiles
        $subfileContents = file_get_contents($subfile);
        preg_match('/\$order\s*=\s*"(.*?)";/', $subfileContents, $subfileOrderMatches);
        $subfileOrder = $subfileOrderMatches[1] ?? null;

        // Remove hyphens and add colon after the main part of the title
        $subfileTitle = str_replace('-', ' ', $subfileTitle);

        // Separate the main part (before the colon) and the rest of the title
        $parts = explode(' ', $subfileTitle, 2); // Split into two parts: main and description
        $mainPart = $parts[0]; // This is the first word (e.g., "Aristotele")
        $description = isset($parts[1]) ? $parts[1] : ''; // Everything after the first space (e.g., "l etica")

        // Combine the main part with colon and the description
        $formattedTitle = ucfirst($mainPart) . ": " . $description;

        $subfileLink = "$root/$menupath/{$filename}/{$subfileName}";
        echo "<li style=\"order:$subfileOrder\"><a href=\"{$subfileLink}\">{$formattedTitle}</a></li>";
      }
      echo "</ul>"; // End sublist
    }
  }
  // End the list item for the menu
  echo "</li>\n";
}
?>

That you can call in a place of the whole menu with a code like this:

 $menupath="your/relative-path";
 include "menu-automatic.inc"; 

Where menu-automatic.inc is the name of the file containing the above code.

Automatic images gallery

With flickity and php you can realize an automatic images gallery, with automatic titles and (if they are present) metatags:

<div id="gallery" style="width: 50%; margin-left: auto; margin-right: auto; margin-bottom: 4%;">
<div class="carousel" title="cliccare su una immagine per ingrandirla" data-flickity='{ "cellAlign": "center", "contain": true, "fullscreen": true, "wrapAround": true, "lazyLoad": 1 }'>

<?php

$images = glob("your-images-path/*.jpg");
$flag=1;

foreach($images as $image)
{
  // Ricava il titolo dell'immagine (metatag o nome del file)
  $imagedescription = '';
  if (function_exists('exif_read_data')) {
    $exifData = exif_read_data($image);

    // Controlla se esiste un campo di commento o descrizione
    if (isset($exifData['ImageDescription'])) {
      $imagedescription = $exifData['ImageDescription']; // Titolo o descrizione nell'EXIF
    }
  }

  $imageTitle = '';

  // Verifica se la funzione IPTC è disponibile
  if (function_exists('iptcparse')) {
    // Ottieni i metadati IPTC dall'immagine
    $iptcData = iptcparse(@iptcembed('', $image)); // iptcembed recupera i metadati IPTC da un'immagine

    // Controlla se il campo "headline" (titolo) è presente nei metadati IPTC
    if (isset($iptcData[2])) {
      $imageTitle = $iptcData[2][0]; // Il campo 2 è "headline" nell'IPTC
      // Troncamento del titolo se troppo lungo
      $maxLength = 50; // Lunghezza massima del titolo
      if (strlen($imageTitle) > $maxLength) {
        $imageTitle = substr($imageTitle, 0, $maxLength) . '...';
      }
    }
  }

  // Se non c'è un titolo IPTC, usa il nome del file senza trattini
  if (empty($imageTitle)) {
    $imageTitle = pathinfo($image, PATHINFO_FILENAME); // Ottieni il nome del file senza estensione

    // Rimuovi trattini dal nome del file, se presenti
    $imageTitle = str_replace('-', ' ', $imageTitle);
  }


  echo '<div class="carousel-cell' .($flag?' active':''). '">';
  echo '<img title="'. $imagedescription .'" data-flickity-lazyload="'. $image .'" onclick="onClick(this)" />';
  echo "<span class='carusel-image-title'>$imageTitle</span>";
  echo '</div>';
  $flag=0;
}
?>

</div>
</div>

php include: no absolute path

To get include command working you should avoid an absolute path: i.g. not

http://somepath/somefile

But, i.g.:

../somepath/somefile

2) In localhost it would be possible this workaround:

$yourvariablepath = realpath($_SERVER["DOCUMENT_ROOT"] . "/a/path");

But this doesn’t work in remote.

3) Another workaround to include a content from a file in another absolute path could be the object tag:

<object data=”your-file-even-on-another-server” />

But an object in another page is an island, a stranger “guest”, without any sharing with the “host” page.

4) Another way (for short text) is to use javascript.