“enter” key in phpmyadmin

If, in show view (not editing a single item) of PhpMyAdmin (i.g. with Firefox), you have a strange behavior of enter key, that is if enter add a new row inside a column, instead of confirm modifications you made, you can try to modify absolute right click settings.
In this way: Run on sites with restrictions -> Don’t Allow

Now your PhpMyAdmin should work as expected.

Fix a corrupt innodb

Today happened that mariadb worked almost correctly, but two wordpress db were incorrectly managed. Indeed I could modify a post, but I couldn’t add a new one.

In another PC I, luckily, had the good wp db (perfectlty working with its innodb). So, it was possible to fix this problem. With the following steps:

a) in the well working device dump (from a teminal) the working wp db:

mysqldump -u root -p --single-transaction --routines --triggers your-db-name > dump-yourdbname.sql

b) in the bad working device

  • activate (if not already active) mariadb
  • in a terminal: mysql -u root -p (of course you have to provide your mysql psw)
  • and then, within mysql, you have to delete the old, bad, db, and create a new one:
    • DROP DATABASE IF EXISTS yourdbname;
    • CREATE DATABASE yourdbname CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    • EXIT;
  • Now you have a new, good but empty db. You have now to import the content of it, with this code: mysql -u root -p yourdbname < dump-yourdbname.sql

Now all should work 🙂.

mysql multiple tables rename

To rename many mysql/mariadb tables with a same prefix, you can uso this script (in a terminal)

mysql -u root -p -N -e " SELECT CONCAT('RENAME TABLE \', table_name, '\ TO \', REPLACE(table_name, 'oldprefix_', 'newprefix_'), '\;') FROM information_schema.tables WHERE table_schema = 'your-database' AND table_name LIKE 'oldprefix_%'; " > renamed.sql 

In this way will created the file renamed.sql (same tables, with different names), that you then can use to replace your database, with

mysql -u root -p yourdatabase < renamed.sql

If you have a wordpress database you have also to check options and meta tables, removing oldprefixes, with:

UPDATE oldprefix_options
SET option_name = REPLACE(option_name, 'oldprefix_', 'newprefix_')
WHERE option_name LIKE 'oldprefix\_%';

and

UPDATE abc_usermeta
SET meta_key = REPLACE(meta_key, 'oldprefix_', 'newprefix_')
WHERE meta_key LIKE 'oldprefix\_%';

And finally, you could check if there are any oldprefix, in options with

SELECT option_name FROM newprefix_options WHERE option_name LIKE 'oldprefix\_%';

same for meta:

SELECT meta_key FROM newprefix_usermeta WHERE meta_key LIKE 'oldprefix\_%';

Innodb: pros and cons

If you have to sync different devices you could have many problems with Innodb engine.

But on the other hand, it has some advantages: is more modern than MyIsam, and support foreign keys.

A compromise can be have Innodb as engine, but all the tables in MyIsam.
You should in any way be careful with some files, as already explained, in particular ibdata1.

how get rid of Innodb

If you don’t need foreign kayes, you can get rid of Innodb in /etc/my.cnf, with these instructions (stop mariadb before, and restart after):

default-storage-engine=MyISAM


Webtrees problems

Webtrees is a fork of PhpGedView, an excellent genealogy program. It ha a big problem: uploading and setting multimedial files.
It’s often a terrible waste of time: a very complicated way to upload files.

workaround

  • You can try to upload images (if you work in localhost and you know what you are doing) in this way:
  • 1. symlink an image to /media folder in /data webtrees folder.
  • 2. add that image file in phpmyadmin (your webtrees db) “media” and “media_file” tables (you have to set a number, such as X110).
    3. add to “individuals” the id of that file, with a code like “1 OBJE @X110@” at the bottom of the field i_gedcom.
  • 4. Now, in webtrees grafical view you has now to (pretend to) modify (nothing modifying, in fact) and save this modification.
  • 5. You could have also to save the modification date (saving the proposed one).

caveat

  • a. The file symlinked must have rights permissions (owner rw, group and others only r).
  • b. no avif: only jpg or webp are allowed.

You should now see the expected image within the page of that individual

Table relations lost in phpmyadmin

If it happen that relations between tables don’t work anymore, you can try (very carefully, and after complete a backup), if you have a backup of them, to replace the files

ibdata1  e ib_logfile0

after stopping mariadb (or mysql). At your own risk: with no guarantee.

PhpMyAdmin: wildcards as default in search tab

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 %...%',

to
return [
'LIKE %...%',
'LIKE',


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.

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.