It can happen that Webtrees gives an error such the following
SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value
You can try to solve it, assigning an auto-increment default value to that field, in PhpMyAdmin
a thoughtful use of digital
It can happen that Webtrees gives an error such the following
SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value
You can try to solve it, assigning an auto-increment default value to that field, in PhpMyAdmin
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>
The new PhpMyAdmin, the 5.2.3, unlike the previous, the 5.2.2, has “like” instead of “like %…%” as default search command.
If you prefer the previous default you can do it following these instructions .
I managed to bo back to the previous default modifying only the file phpMyAdmin/libraries/classes/Types.php
at rows 99 -100
from
return [
'LIKE',
'LIKE %...%',
toreturn [
'LIKE %...%',
'LIKE',
Html5 helps to use semantic tags, but only in some cases.
I.g. for a date you can use <time>
<p>La conferenza si terrà il <time datetime="2025-11-14">14 novembre 2025</time>.</p>
Far more complicated is the way for the books. There is not a tag such as <book>. Unfortunately, the Internet is not for the truth, but for commercial purposes, so you have to follow a very long and annoying way:
<h1>List of Books</h1>
<div itemscope itemtype="http://schema.org/Book">
<h2 itemprop="name">The Great Gatsby</h2>
<img src="cover-gatsby.jpg" alt="Cover of The Great Gatsby" itemprop="image">
<p itemprop="author">F. Scott Fitzgerald</p>
<p itemprop="description">The Great Gatsby is a novel written by F. Scott Fitzgerald and published in 1925. The story is set in 1922 during the Jazz Age and the economic prosperity of the United States.</p>
</div>
<div itemscope itemtype="http://schema.org/Book">
<h2 itemprop="name">1984</h2>
<img src="cover-1984.jpg" alt="Cover of 1984" itemprop="image">
<p itemprop="author">George Orwell</p>
<p itemprop="description">1984 is a dystopian novel written by George Orwell and published in 1949. The story is set in a future dystopia where the totalitarian government controls every aspect of citizens' lives.</p>
</div>
<div itemscope itemtype="http://schema.org/Book">
<h2 itemprop="name">Moby Dick</h2>
<img src="cover-moby-dick.jpg" alt="Cover of Moby Dick" itemprop="image">
<p itemprop="author">Herman Melville</p>
<p itemprop="description">Moby Dick is a novel written by Herman Melville and published in 1851. The story follows the obsessive quest of Captain Ahab to hunt down the white whale, Moby Dick.</p>
</div>
another example:
<tr itemscope itemtype="http://schema.org/Book"><td><span itemprop="name">Traumdeutung</span></td>
<td><span itemprop="alternativeHeadline"> L'interpretazione dei sogni</span></td><td><span itemprop="datePublished" content="1900">1900</span></td></tr>
<tr itemscope itemtype="http://schema.org/Book"><td><span itemprop="name">Zur Psychopathlogie des Altagslebens</span></td>
<td><span itemprop="alternativeHeadline"> Psicopatologia della vita quotidiana</span></td><td><span itemprop="datePublished" content="1901">1901</span></td></tr>
<span itemprop=”locationCreated”>
<span itemprop=”bookEdition”> (for Edition)
<span itemprop=”author”> (for Author)
You could use a code like the following:
<div itemscope itemtype="http://schema.org/Movie">
<h1 itemprop="name">The Godfather</h1>
<h2 itemprop="alternateName">Il Padrino</h2>
<img itemprop="image" src="https://example.com/locandina_il_padrino.jpg" alt="Locandina del film Il Padrino">
<p>Regista: <span itemprop="director">Francis Ford Coppola</span></p>
<p>Data di rilascio: <span itemprop="releaseDate">15 marzo 1972</span></p>
</div>
more here.
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.
There is a very simple workaround: adding this row to css
position: sticky;
top: 0;
will-change: transform; /* anti-flickering */
Check if your php version is in apache mods-enabled (in /etc/apache2/mods-enabled).
Your current php should be in /etc/apache2/mods-available but not (if you have several php versions) in /etc/apache2/mods-enabled.
Pro: automation of ads.
Cons: impossible to customize the type of ads. Therefore banal and vulgar advertising.
A script like the following can generate automatically your sitemap (in xml format):
<?php
function genera_sitemap($path) {
$sitemap = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$sitemap .= '<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">' . "\n";
// Scansiona le directory e sottodirectory del sito
$dir = './';
$files = scandir($dir);
foreach ($files as $file) {
if ($file != '.' && $file != '..' && strpos($file, '.') !== 0) {
if (is_dir($dir . $file)) {
// Scansiona la sottodirectory
$sitemap .= aggiungi_sottodirectory($dir . $file . '/', $path) . "\n";
} else {
// Aggiungi il file alla sitemap
if (preg_match('/\.php$/', $file) && $file != 'sql-pass.php') {
$sitemap .= '<url>' . "\n";
$sitemap .= ' <loc>' . $path . '/' . $file . '</loc>' . "\n";
$sitemap .= ' <lastmod>' . date('c', filemtime($dir . $file)) . '</lastmod>' . "\n";
//$sitemap .= ' <changefreq>daily</changefreq>' . "\n";
$sitemap .= ' <priority>1.0</priority>' . "\n";
$sitemap .= '</url>' . "\n";
}
}
}
}
$sitemap .= '</urlset>' . "\n";
// Salva la sitemap su file
$file = 'sitemap.xml';
$fp = fopen($file, 'w');
fwrite($fp, $sitemap);
fclose($fp);
}
function aggiungi_sottodirectory($dir, $path) {
$sitemap = '';
$files = scandir($dir);
foreach ($files as $file) {
if ($file != '.' && $file != '..' && strpos($file, '.') !== 0) {
if ($file == 'index.php') {
$priority = '1.0';}
elseif (preg_match('/testi/', $file)) {
$priority = 0.2;
}
else {
$priority = 0.6;
}
if (is_dir($dir . $file)) {
// Scansiona la sottodirectory
$sitemap .= aggiungi_sottodirectory($dir . $file . '/', $path) . "\n";
} else {
// Aggiungi il file alla sitemap
if (preg_match('/\.php$/', $file)) {
$sitemap .= '<url>' . "\n";
$sitemap .= ' <loc>' . $path . substr($dir, 2) . $file . '</loc>' . "\n";
$sitemap .= ' <lastmod>' . date('c', filemtime($dir . $file)) . '</lastmod>' . "\n";
//$sitemap .= ' <changefreq>daily</changefreq>' . "\n";
$sitemap .= ' <priority>' . $priority . '</priority>' . "\n";
$sitemap .= '</url>' . "\n";
}
}
}
}
return $sitemap;
}
?>
You can call it from different websites, with a code like the following (assuming that your script is genera-sitemap-commune.inc:
<?php
$path="https:[your-desired-path]";
include "genera-sitemap-commune.inc";
genera_sitemap($path);
?>
You can add metadata to a website folder, i.g. adding in it a file, such as . folder, within write something like:
{
"description": "your description",
"order": 2
}
“order”: 2, in case you want that that folder be the second in your webpage
In the webpage you can retrieve the metadata info with a code like this:
<?php
$d = dir(".");
$folders = [];
// Array delle cartelle da escludere
$excludedDirs = ['excluded-dir', 'another-excluded-dir', 'yet-another-excluded-dir'];
while (false !== ($entry = $d->read())) {
// Controlla se l'entry è una directory e non è una delle cartelle da escludere
if (is_dir($entry) && ($entry != '.') && ($entry != '..') && !in_array($entry, $excludedDirs)) {
$metadataFile = $entry . '/.directory';
$metadata = [];
// Recupera i metadati dal file .directory
if (file_exists($metadataFile)) {
$metadata = json_decode(file_get_contents($metadataFile), true); // Leggi e decodifica il contenuto del file
}
// Aggiungi la cartella e i metadati all'array
$folders[] = [
'name' => $entry,
'displayName' => str_replace('-', ' ', $entry), // Sostituisci i trattini con spazi per la visualizzazione
'order' => isset($metadata['order']) ? $metadata['order'] : PHP_INT_MAX, // Usa un valore alto se non è specificato
'description' => isset($metadata['description']) ? $metadata['description'] : ''
];
}
}
// Ordina le cartelle in base all'attributo 'order'
usort($folders, function($a, $b) {
return $a['order'] <=> $b['order'];
});
echo "<h2>sotto-sezioni</h2>\n<ul>";
foreach ($folders as $folder) {
echo "<li order='{$folder['order']}'><a class='big' href='{$folder['name']}'>{$folder['displayName']}</a>";
if ($folder['description']) {
echo "<br /><p>{$folder['description']}</p>"; // Mostra la descrizione se presente
}
echo "</li>";
}
echo "</ul>";
$d->close();
?>