예제 #1
0
/**
 * Recursively search and replace
 * @param mixed $data - **by reference** - string or array which should have find/replace applied
 * @param array $search array with text values to find
 * @param array $replace array with text values to replace $search values with
 * @param array $regex_search array with regular expressions to look for
 * @param array $regex_replace array with text value to replace $regex_search values with
 * @return int number of replacements made
 */
function ns_recursive_search_replace(&$data, $search, $replace, $regex_search = array(), $regex_replace = array(), $case_sensitive = false)
{
    $is_serialized = is_serialized($data);
    $string_replacements_made = $regex_replacements_made = 0;
    // unserialize if need be
    if ($is_serialized) {
        $data = unserialize($data);
    }
    // run through replacements for strings, arrays - other types are unsupported to vaoid
    if (is_array($data)) {
        foreach ($data as $key => $value) {
            ns_recursive_search_replace($data[$key], $search, $replace, $regex_search, $regex_replace, $case_sensitive);
        }
    } elseif (is_string($data)) {
        // simple string replacment - most of the time this is all that is needed
        $replace_func = $case_sensitive ? 'str_replace' : 'str_ireplace';
        $data = $replace_func($search, $replace, $data, $string_replacements_made);
        // advanced regex replacement - this will be skipped most of the time
        if (!empty($regex_search) && !empty($regex_replace)) {
            $data = preg_replace($regex_search, $regex_replace, $data, -1, $regex_replacements_made);
        }
    }
    // reserialize if need be
    if ($is_serialized) {
        $data = serialize($data);
    }
    // return count of replacements made
    return $string_replacements_made + $regex_replacements_made;
}
예제 #2
0
 function clone_tables()
 {
     $this->dlog('ENTER ns_cloner::clone_tables');
     // Setup replacements for standard url/name substitution + character encoding issues
     $search = array($this->source_upload_dir_relative, $this->source_upload_url, $this->source_subd, $this->source_prefix . "user_roles");
     $replace = array($this->target_upload_dir_relative, $this->target_upload_url, $this->target_subd, $this->target_prefix . "user_roles");
     $search = apply_filters('ns_cloner_search_items', $search, $this);
     $replace = apply_filters('ns_cloner_replace_items', $replace, $this);
     $regex_search = apply_filters('ns_cloner_regex_search_items', array(), $this);
     $regex_replace = apply_filters('ns_cloner_regex_replace_items', array(), $this);
     $this->dlog(array("String search targets:", $search));
     $this->dlog(array("String search replacements:", $replace));
     $this->dlog(array("Regex search targets:", $regex_search));
     $this->dlog(array("Regex search replacements:", $regex_replace));
     // Sort and filter replacements to intelligently avoid compounding replacement issues - more details in function comments in lib/ns-utils.php
     if (apply_filters('ns_do_search_replace_validation', true)) {
         ns_set_search_replace_sequence($search, $replace, $regex_search, $regex_replace, NS_CLONER_LOG_FILE_DETAILED);
         $search = apply_filters('ns_cloner_search_items_after_sequence', $search, $this);
         $replace = apply_filters('ns_cloner_replace_items_after_sequence', $replace, $this);
         $regex_search = apply_filters('ns_cloner_regex_search_items_after_sequence', $regex_search, $this);
         $regex_replace = apply_filters('ns_cloner_regex_replace_items_after_sequence', $regex_replace, $this);
         $this->dlog(array("String search targets after sequence:", $search));
         $this->dlog(array("String search replacements after sequence:", $replace));
         $this->dlog(array("Regex search targets after sequence:", $regex_search));
         $this->dlog(array("Regex search replacements after sequence:", $regex_replace));
     }
     // Fetch source tables and start cloning
     $tables = $this->get_site_tables($this->source_db, $this->source_prefix);
     $count_tables_cloned = $count_replacements_made = 0;
     if (is_array($tables) && count($tables) > 0) {
         foreach ($tables as $source_table) {
             // if it's a non-prefixed table (root/main), prepend the prefix on, otherwise do replacement
             if (strpos($source_table, $this->source_prefix) === false) {
                 $target_table = $this->target_prefix . $source_table;
             } else {
                 $target_table = str_replace($this->source_prefix, $this->target_prefix, $source_table);
             }
             $quoted_source_table = ns_sql_backquote($source_table);
             $quoted_target_table = ns_sql_backquote($target_table);
             $structure_query = "SHOW CREATE TABLE " . $quoted_source_table;
             $structure = $this->source_db->get_var($structure_query, 1, 0);
             $this->handle_any_db_errors($this->source_db, $query);
             // If table references another table not yet created, save it for the end
             $reference_exists = preg_match_all("/REFERENCES `{$this->source_prefix}([^`]+?)/", $structure, $reference_matches);
             if ($reference_exists) {
                 foreach ($reference_matches[1] as &$referenced_table) {
                     $current_pos = array_search($source_table, $tables);
                     $completed_tables = array_slice($tables, 0, $current_pos);
                     if (!in_array($referenced_table, $completed_tables)) {
                         unset($tables[$currrent_pos]);
                         array_push($tables, $source_table);
                         $this->dlog("Moving table <b>{$source_table}</b> to end of cloning queue due to dependent constraint");
                         continue 2;
                     }
                 }
             }
             // Log which table this is (and don't copy a table to itself if for some reason prefix didn't change)
             $this->dlog_break();
             if ($source_table == $target_table) {
                 $this->dlog("Source table: <b>{$source_table}</b> and Target table: <b>{$target_table} are the same! SKIPPING!!!</b>");
                 continue;
             } else {
                 $this->dlog("Cloning source table: <b>{$source_table}</b> to Target table: <b>{$target_table}</b>");
             }
             $this->dlog_break();
             // Drop the target table if it already exists to avoid conflicts
             if (apply_filters('ns_cloner_do_drop_target_table', true, $target_table, $this)) {
                 $query = "DROP TABLE IF EXISTS " . $quoted_target_table;
                 $this->target_db->query($query);
                 $this->handle_any_db_errors($this->target_db, $query);
             }
             // Create cloned table structure (and rename any constraints to prevent errors)
             $query = str_replace($quoted_source_table, $quoted_target_table, $structure);
             $query = preg_replace("/REFERENCES `{$this->source_prefix}/", "REFERENCES `{$this->target_prefix}", $query);
             $query = preg_replace("/CONSTRAINT `.+?`/", "CONSTRAINT", $query);
             $this->target_db->query(apply_filters('ns_cloner_create_table_query', $query, $this));
             $this->handle_any_db_errors($this->target_db, $query);
             // Get table contents
             $query = "SELECT * FROM " . $quoted_source_table;
             $contents = $this->source_db->get_results($query, ARRAY_A);
             $this->handle_any_db_errors($this->source_db, $query);
             $this->dlog("Number of rows: " . count($contents));
             $row_counter = 0;
             $rows_to_insert = array();
             foreach ($contents as $row) {
                 $row_counter++;
                 $insert_this_row = true;
                 // set flag to skip any junk rows which shouldn't/needn't be copied
                 // we can't use 'continue' here because if this is the last row in a batch insert that query still needs to happen
                 if (isset($row['option_name']) && preg_match('/(_transient_rss_|_transient_(timeout_)?feed_)/', $row['option_name']) || isset($row['meta_key']) && preg_match('/(_edit_lock|_edit_last)/', $row['meta_key']) || !apply_filters('ns_cloner_do_copy_row', true, $row, $source_table)) {
                     $insert_this_row = false;
                 }
                 // only spend resources on replacements if this row is going to be inserted
                 if ($insert_this_row) {
                     // make sure target title option doesn't get lost/replaced
                     if (preg_match('/options$/', $target_table) && isset($row['option_name']) && $row['option_name'] == 'blogname' && !empty($this->target_title)) {
                         $row['option_value'] = $this->target_title;
                     }
                     // perform replacements
                     foreach ($row as $field => $value) {
                         $row_count_replacements_made = ns_recursive_search_replace($value, $search, $replace, $regex_search, $regex_replace, isset($this->request['case_sensitive']));
                         $row[$field] = apply_filters('ns_cloner_field_value', $value, $field, $row, $this);
                         $count_replacements_made += $row_count_replacements_made;
                     }
                     $row = apply_filters('ns_cloner_insert_values', $row, $target_table);
                 }
                 // one by one insertion is less efficient - only do if explicitly set in code elsewhere via filter
                 if (apply_filters('ns_cloner_single_insert', false, $this, $target_table)) {
                     if ($insert_this_row) {
                         $format = apply_filters('ns_cloner_insert_format', null, $target_table);
                         $this->target_db->insert($target_table, $row, $format);
                         $this->handle_any_db_errors($this->target_db, "INSERT INTO {$target_table} via wpdb --> " . print_r($row, true));
                         do_action('ns_cloner_after_insert', $rows, $target_table);
                     }
                 } else {
                     if ($insert_this_row) {
                         array_push($rows_to_insert, $row);
                     }
                     if ($row_counter % 100 === 0 || $row_counter === count($contents)) {
                         // avoid trying to insert with no values
                         if (empty($rows_to_insert)) {
                             continue;
                         }
                         // we are go to insert, so create query and execute
                         $column_names = array_keys($row);
                         $query = "INSERT INTO {$quoted_target_table} (" . implode(",", ns_sql_backquote($column_names)) . ") VALUES ";
                         foreach ($rows_to_insert as $row_to_insert) {
                             $values = array_map('ns_sql_quote', $row_to_insert);
                             $query .= "(" . implode(",", $values) . "),";
                         }
                         $rows_to_insert = array();
                         $query_with_ending = substr($query, 0, -1) . ';';
                         $this->target_db->query($query_with_ending);
                         $this->handle_any_db_errors($this->target_db, $query_with_ending);
                         do_action('ns_cloner_after_insert_batch', $rows_to_insert, $target_table);
                     }
                 }
             }
             // end rows loop
             $count_tables_cloned++;
         }
         // end tables loop
         $this->report[__('Tables cloned', 'ns-cloner')] = $count_tables_cloned;
         $this->report[__('Replacements made', 'ns-cloner')] = $count_replacements_made;
         $this->dlog('Cloned: <b>' . $count_tables_cloned . '</b> tables!');
         $this->dlog('Replaced: <b>' . $count_replacements_made . '</b> occurences of search strings!');
     } else {
         $this->dlog('No tables found for cloning');
     }
 }