Archiv für den Monat: September 2013

WordPress Update: Use local file

My WordPress installation couldn’t download the necessary update files fast enough. I could see that in wp-content/tmp the .tmp-files were created and growing, but they all stopped early and WordPress tried downloading again and again. Of course, your WordPress-installation might use a different tempdir. If you’re unsure, just add the following line to your wp-config.php to make sure that the tempdir is exactly what you expect:

define('WP_TEMP_DIR', ABSPATH . 'wp-content/tmp');

Here’s what you have to do:

  1. Download the update manually and upload it to the server into the directory wp-content/tmp.
  2. Modify the file wp-admin/includes/file.php by adding these five lines to the function download_url, right before the line with the call to wp_safe_remote_get().
    $parts = parse_url($url);
    if ( empty($dir) )
        $dir = get_temp_dir();
    if (file_exists($dir . $parts['path']))
        return $dir . $parts['path'];
  3. Run the „Automatic Update“ from your dashboard.

Please keep these things in mind:

  • The file that you stored into the wp-content/tmp will be deleted after the upgrade.
  • The changes to file.php will disappear as the upgrade normally overwrites file.php

How does this work?

We extract the filename from the URL that WordPress is trying to download ($parts['path'] is the filename). If the file resides in the tempdir, simply return with this filename rather than with a temporary filename.

Sortierung von mysql ist anders als die Sortierung von bash

Um schnell prüfen zu können, ob ein Element in einer Datenbank-Tabelle enthalten ist, ohne dafür jedesmal die Datenbank abzufragen, wollte ich diese eine Tabelle, deren Inhalt ich prüfen wollte, in einem bash-Array ablegen.

Die Datenbank-Tabelle hat folgenden Inhalt (neben der ID):

AR
ÄR
ZZ
XÉ
XÉ F
XE, J
XÉ; P
XÉ; S

Übernehmen kann man den Inhalt der mysql-Tabelle in einem bash-Script eigentlich ganz leicht:

while read line
do
  tablearray+=("${line}")
done <<(${mysqlcmd} -Bse "select name from table order by name")

Um nun auch schnell prüfen zu können, ob ein Element bereits in dem Array enthalten ist, wollte ich ungern alle Elemente durchlaufen. Stattdessen lasse ich bereits mysql die Daten sortieren. Im bash-Script selbst „suche“ ich dann über einen Binären-Suchbaum-Ansatz innerhalb des Bash-Arrays:

function contains()
{
  declare -a haystack=("${!2}")
  local needle=${1}
  local low=0
  local lowold=0
  local high=${#haystack[@]}
  local highold=${#haystack[@]}
  let "pos = high / 2"
  while true
  do
    if [[ "${haystack[${pos}]}" == "${needle}" ]]; then
      # Found
      return 0
    fi
    if [ "${haystack[${pos}]}" \> "${needle}" ]; then
      let "high = pos"
      let "pos = low + ( high - low ) / 2"
    else
      let "low = pos"
      let "pos = low + ( high - low ) / 2"
    fi
    if [ ${highold} -eq ${high} ]; then
      if [ ${lowold} -eq ${low} ]; then
        # Not found
        return 1
      fi
    fi
    let "lowold = low"
    let "highold = high"
  done
}

Aufrufen kann man diese Funktion bequem innerhalb des Scripts mit:

  if contains "SearchString" tablearray[@] ; then

Nebeneffekt hierbei ist allerdings, dass lokal eine Kopie des Arrays angelegt wird. Wer das nicht möchte, muss den Teil declare -a haystack=("${!2}") auslassen und statt $haystack immer auf den Original-Array verweisen. Das führt auch leider dazu, dass man für jedes Array eine eigene Funktion braucht…

Bei einigen Suchen konnte das Element nicht gefunden werden (obwohl es im Array enthalten war) und – noch schlimmer – das contains() lief in einer Endlos-Schleife weiter. Nach kurzer Analyse war klar, dass die Sortierung von bash eine andere ist als das, was mysql verwendet.

Ich hatte schon vermutet, dass es wahrscheinlich an den CHARSET oder COLLATE bzw. COLLATION von mysql liegt, und habe mir daher ein bash-Script geschrieben, welches prüft, welche Kombinationen genauso sortieren wie bash. Wer Interesse hat, kann sich das Script gerne herunterladen: mysql_collate.sh

Das Skript überprüft dabei zwei Dinge gleichzeitig:

  1. Sind die Sonderzeichen korrekt in die Datenbank eingespeichert worden und können auch korrekt wieder ausgelesen werden?
  2. Ist die Sortierung von bash mit der mysql-„ORDER BY“ Klausel kompatibel?

Auf meinem System:

$ mysql --version
mysql  Ver 14.14 Distrib 5.5.32, for debian-linux-gnu (x86_64) using readline 6.2

Erhalte ich folgende gültige Kombinationen:

dec8 / dec8_bin
cp850 / cp850_bin
hp8 / hp8_english_ci
hp8 / hp8_bin
latin1 / latin1_bin
latin2 / latin2_bin
ujis / ujis_japanese_ci
ujis / ujis_bin
cp1250 / cp1250_bin
latin5 / latin5_bin
utf8 / utf8_bin
utf8 / utf8_icelandic_ci
ucs2 / ucs2_bin
ucs2 / ucs2_icelandic_ci
keybcs2 / keybcs2_bin
macce / macce_bin
macroman / macroman_bin
cp852 / cp852_bin
latin7 / latin7_bin
utf8mb4 / utf8mb4_icelandic_ci
utf16 / utf16_icelandic_ci
cp1257 / cp1257_bin
utf32 / utf32_bin
utf32 / utf32_icelandic_ci
eucjpms / eucjpms_japanese_ci
eucjpms / eucjpms_bin

Ein wenig unangenehm ist mir das schon, aber ich arbeite nun mit einem binären Ansatz und habe für meine Zwecke latin1 / latin1_bin ausgewählt.