2012-04-26 2 views
7

Attualmente sto ristrutturando il mio sito Web personalizzato su un CMS basato su WordPress.Scrittura di uno script di ricerca/sostituzione di un database MySQL in PHP

Il sito Web su cui ho lavorato è semplicemente il mio URL esistente più /dev/, ovvero http://my.website.com/dev/.

Sposterò questo sito web per il http://my.website.com durante il fine settimana e, come tale, sarà necessario rimuovere tutti i riferimenti all'URL /dev/.

Quello che mi piacerebbe fare è, fondamentalmente, un "trovare e sostituire" per /dev sul mio database. Riesco a vedere esattamente in quali tabelle è presente questo valore, ma naturalmente, come in un'installazione di WordPress, molti di questi campi sono dati serializzati, il che si interromperà direttamente con un semplice dump>open with notepad++>find & replace.

Il codice che ho sviluppato per questo scopo è qui:

<?php 

$look_at[] = array("table" => "wp_options", "fields" => array("option_value"), "id_field" => "option_id"); 
$look_at[] = array("table" => "wp_postmeta", "fields" => array("meta_value"), "id_field" => "meta_id"); 
$look_at[] = array("table" => "wp_posts", "fields" => array("post_content", "guid"), "id_field" => "ID"); 
$look_at[] = array("table" => "wp_sfmeta", "fields" => array("meta_value"), "id_field" => "meta_id"); 
$look_at[] = array("table" => "wp_sfoptions", "fields" => array("option_value"), "id_field" => "option_id"); 
$look_at[] = array("table" => "wp_sferrorlog", "fields" => array("error_text"), "id_field" => "id"); 

for ($i = 0; $i < sizeof ($look_at); $i++) { 
    foreach($look_at[$i]["fields"] as $field) { 

     $sql = 'SELECT `' . $field . '`, `' . $look_at[$i]["id_field"] . '` FROM `' . $look_at[$i]["table"] . '`;'; 
     $res = mysql_query($sql); 

     while ($row = mysql_fetch_assoc($res)) { 

      $table = $look_at[$i]["table"]; 
      $id_field = $look_at[$i]["id_field"]; 
      $old_val = $row[$field]; 
      $id = $row[$id_field]; 

      $unserialized_value = @unserialize($old_val); 

      if ($old_val === 'b:0;' || $unserialized_value !== false) 
       $new_val = serialize(str_replace(array("/dev/", "/dev"), array("/", ""), $unserialized_value)); 
      else 
       $new_val = str_replace(array("/dev/", "/dev"), array("/", ""), $old_val); 

      $update_array[] = array("id_field" => $id_field, "id" => $id, "table" => $table, "key" => $key, "old_val" => $old_val, "new_val" => $new_val); 

     } 

    } 
} 

for ($i = 0; $i < sizeof($update_array); $i++) { 
    if ($update_array[$i]["old_val"] !== $update_array[$i]["new_val"]) 
     $updated_sql .= 'UPDATE ' . $update_array[$i]["table"] . ' SET `' . $update_array[$i]["key"] . '` = \'' . $update_array[$i]["new_val"] . '\' WHERE `' . $update_array[$i]["id_field"] . '` = \'' . $update_array[$i]["id"] . '\';'; 
} 

mysql_query($updated_sql); 

?> 

Un esempio dei dati serializzati:

a:6:{s:5:"width";s:3:"400";s:6:"height";s:3:"530";s:14:"hwstring_small";s:22:"height='96' width='72'";s:4:"file";s:30:"2011/12/Amazonas-English-1.jpg";s:5:"sizes";a:13:{s:9:"thumbnail";a:3:{s:4:"file";s:30:"Amazonas-English-1-125x165.jpg";s:5:"width";s:3:"125";s:6:"height";s:3:"165";}s:6:"medium";a:3:{s:4:"file";s:30:"Amazonas-English-1-339x450.jpg";s:5:"width";s:3:"339";s:6:"height";s:3:"450";}s:5:"large";s:0:"";s:14:"post-thumbnail";a:3:{s:4:"file";s:30:"Amazonas-English-1-125x165.jpg";s:5:"width";s:3:"125";s:6:"height";s:3:"165";}s:23:"indexleft-species-thumb";a:3:{s:4:"file";s:30:"Amazonas-English-1-200x265.jpg";s:5:"width";s:3:"200";s:6:"height";s:3:"265";}s:13:"species-thumb";a:3:{s:4:"file";s:30:"Amazonas-English-1-288x381.jpg";s:5:"width";s:3:"288";s:6:"height";s:3:"381";}s:17:"indexheader-thumb";a:5:{s:4:"file";s:30:"Amazonas-English-1-400x300.jpg";s:5:"width";s:3:"400";s:6:"height";s:3:"300";s:4:"path";s:38:"2011/12/Amazonas-English-1-400x300.jpg";s:3:"url";s:88:"http://www.xxxxxxxxxxx.com/dev/wp-content/uploads/2011/12/Amazonas-English-1-400x300.jpg";}s:14:"random-thumb-1";a:3:{s:4:"file";s:28:"Amazonas-English-1-56x75.jpg";s:5:"width";s:2:"56";s:6:"height";s:2:"75";}s:14:"random-thumb-2";a:3:{s:4:"file";s:29:"Amazonas-English-1-75x100.jpg";s:5:"width";s:2:"75";s:6:"height";s:3:"100";}s:14:"random-thumb-3";a:3:{s:4:"file";s:29:"Amazonas-English-1-94x125.jpg";s:5:"width";s:2:"94";s:6:"height";s:3:"125";}s:14:"random-thumb-4";a:3:{s:4:"file";s:30:"Amazonas-English-1-113x150.jpg";s:5:"width";s:3:"113";s:6:"height";s:3:"150";}s:14:"random-thumb-5";a:3:{s:4:"file";s:30:"Amazonas-English-1-132x175.jpg";s:5:"width";s:3:"132";s:6:"height";s:3:"175";}s:13:"d4p-bbp-thumb";s:0:"";}s:10:"image_meta";a:10:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";}} 

EDIT ULTERIORI

Purtroppo, ci sono altre istanze di /dev/ in o ther array serializzati, come questo esempio:

'a:1:{i:0;a:5:{s:4:"type";s:5:"image";s:3:"loc";s:107:"/home/xxxxx/domains/xxxxxxxxx.com/public_html/dev/wp-content/sp-resources/forum-image-uploads/matt/2012/01/";...

Oppure,

a:1:{i:0;a:5:{s:4:"data";s:88:"Your search - <b>link:http://www.xxxxxxxxx.com/dev/</b> - did not match any documents. ";...

Come tale, non credo che un semplice preg_replace (o callback) farà il trucco, ma Immagino che uno avanzato potrebbe?


Le mie domande sono:

  1. C'è un modo più semplice di fare questo ?!
  2. Il codice sopra riportato può causare problemi?

Sono pessimo di fronteggiare problemi con il mio codice (programmatore malvagio, mi scuso) e in quanto tale un po 'preoccupato di eseguire test con questo codice.


montaggio finale: CODICE DI LAVORO

Perché il mio dump SQL era quasi 100mb, ho dovuto usare WAMP con la memoria illimitata.

<?php 
    error_reporting(E_ALL); 
    ini_set('display_errors', 'On'); 
    ini_set('memory_limit', '-1'); 

    $handle = @fopen("amend-this.sql", "r"); 
    if ($handle) { 
     while (($buffer = fgets($handle, 4096)) !== false) { 
      $newLine = preg_replace_callback('@s:(\d+)(:\\\"[^"]*www.seriouslyfish\.com)/[email protected]', create_function('$matches', 'return \'s:\'.($matches[1] - 4).$matches[2];'), $buffer); 
      $newLine = preg_replace_callback('@s:(\d+)(:\\\"[^\\\"]*/home/sfish/domains/seriouslyfish\.com/public_html)/[email protected]', create_function('$matches', 'return \'s:\'.($matches[1] - 4).$matches[2];'), $newLine); 
      $newLine = str_replace('http://dunc.seriouslyfish.com/dev/', 'http://www.seriouslyfish.com/', $newLine); 
      $newLine = str_replace('http://www.seriouslyfish.com/dev/', 'http://www.seriouslyfish.com/', $newLine); 
      $newLine = str_replace('/dev', '', $newLine); 
      file_put_contents("amended.sql", $newLine, FILE_APPEND); 
     } 
     fclose($handle); 
    } 
?> 

Questo codice messo il mio nuovo file SQL nella stessa directory (X:\wamp\www) per me di manipolare ulteriormente.

ho avuto alcuni problemi con i dati ripetizione, e ci sono stati 67 casi di /dev ancora nel file, per qualche motivo, ma ho usato Notepad++ e WinMerge per ordinare tutto questo fuori e alla fine mi ci sono voluti circa 45 minuti per cercare/sostituire un database di oltre 90 milioni di caratteri.

+0

Cosa stai cercando di dichiarare $ look_at []? –

+0

Specificare le tabelle/i campi da esaminare quando si esegue il comando Trova/Sostituisci. Ci sono un certo numero di campi su un certo numero di tabelle che non conterranno mai alcun riferimento a '/ dev'. – dunc

risposta

6

Quando ho avuto lo stesso problema, ho eseguito un mysqldump del database, quindi aperto in un editor di testo e ho cercato/sostituito i valori, prima di utilizzare l'SQL per creare il nuovo database. Abbastanza semplice, sorprendentemente veloce, soprattutto per una tantum.

Come sottolineato, si ha il problema con dati serializzati, in modo che si possa fare una cosa simile con un semplice file PHP:

<?php 
$handle = @fopen("/tmp/dump.sql", "r"); 
if ($handle) { 
    while (($buffer = fgets($handle, 4096)) !== false) { 
     $newLine = preg_replace_callback('@s:(\d+)(:\\\"[^"]*xxxxxxxxxxx\.com)/[email protected]', create_function('$matches', 'return \'s:\'.($matches[1] - 4).$matches[2];'), $buffer); 
     $newLine = preg_replace_callback('@s:(\d+)(:\\\"[^\\\"]*xxxxxxxxxxx\.com/public_html)/[email protected]', create_function('$matches', 'return \'s:\'.($matches[1] - 4).$matches[2];'), $newLine); 
     $newLine = str_replace('http://www.xxxxxxxxxxx.com/dev/', 'http://www.xxxxxxxxxxx.com/', $newLine); 
     echo $newLine; 
    } 
    fclose($handle); 
} 
?> 

Nota: questo funziona su un mysqldump, se siete test, è necessario rimuovere il prima del " s nel preg_replace_callback s - questo è solo mysqldump di escape citazioni.

Nota anche: Sono presenti due sostituimenti di pref (uno per gli URL normali e uno per i percorsi del server) e uno sostituisce per gli URL standard rimasti.

+0

Ciao Leonard. Sfortunatamente, se lo faccio, romperà i miei dati serializzati. La funzione 'serialize' di PHP conta sulla lunghezza delle stringhe contenute nel suo array, cioé' .com/dev/'è di 9 caratteri,' .com' è solo 4. PHP non riuscirà quindi a riconoscere i dati serializzati come serializzati se il il formato/le lunghezze non sono corretti. – dunc

+0

Ahh - Se ricordo male ho usato dev.domain.tld e cambiato in www.domain.tld - mi dispiace per quello. Se sono onesto, il mio prossimo passo sarebbe vedere se posso cercare ad un livello più alto, cambiare i dati serializzati per avere la giusta lunghezza. – LeonardChallis

+0

Sì, è quello che sto cercando di fare con il codice PHP, dato che non sono a conoscenza di nessun editor di testo che possa gestire i dati serializzati. – dunc

0

Non potresti usare solo la CLI WP per questo?

wp search-replace https://example.dev https://example.com