site_oueb_2/DBSR-master/compiled/DBSearchReplace-CLI.php

17 lines
33 KiB
PHP
Executable File

<?php
/* This file is part of DBSR.
*
* DBSR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DBSR is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DBSR. If not, see <http://www.gnu.org/licenses/>.
*/
class DBSR{const VERSION='2.2.0';const OPTION_CASE_INSENSITIVE=0;const OPTION_EXTENSIVE_SEARCH=1;const OPTION_SEARCH_PAGE_SIZE=2;const OPTION_VAR_MATCH_STRICT=3;const OPTION_FLOATS_PRECISION=4;const OPTION_CONVERT_CHARSETS=5;const OPTION_VAR_CAST_REPLACE=6;const OPTION_DB_WRITE_CHANGES=7;const OPTION_HANDLE_SERIALIZE=8;const OPTION_REVERSED_FILTERS=9;const OPTION_LOCK_TABLES=10;public static function createClass($className){if(!class_exists($className,false)){$classArray=explode('\\',$className);if(count($classArray)>1){$className=array_pop($classArray);$namespace=implode('\\',$classArray);eval('namespace '.$namespace.' { class '.$className.' {} }');}else{eval('class '.$className.' {}');}}}public static function getPHPType($mysql_type){$types=array('/^\s*BOOL(EAN)?\s*$/i'=>'boolean','/^\s*TINYINT\s*(?:\(\s*\d+\s*\)\s*)?$/i'=>'integer','/^\s*SMALLINT\s*(?:\(\s*\d+\s*\)\s*)?$/i'=>'integer','/^\s*MEDIUMINT\s*(?:\(\s*\d+\s*\)\s*)?$/i'=>'integer','/^\s*INT(EGER)?\s*(?:\(\s*\d+\s*\)\s*)?$/i'=>'integer','/^\s*BIGINT\s*(?:\(\s*\d+\s*\)\s*)?$/i'=>'integer','/^\s*FLOAT\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float','/^\s*DOUBLE(\s+PRECISION)?\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float','/^\s*REAL\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float','/^\s*DEC(IMAL)?\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float','/^\s*NUMERIC\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float','/^\s*FIXED\s*(?:\(\s*\d+\s*(?:,\s*\d+\s*)?\)\s*)?$/i'=>'float',);foreach($types as $regex=>$type){if(preg_match($regex,$mysql_type)){return $type;}}return 'string';}protected $pdo;private $_pdo_charset;private $_pdo_collation;private $_dbr_callback;protected $options=array(self::OPTION_CASE_INSENSITIVE=>false,self::OPTION_EXTENSIVE_SEARCH=>false,self::OPTION_SEARCH_PAGE_SIZE=>10000,self::OPTION_VAR_MATCH_STRICT=>true,self::OPTION_FLOATS_PRECISION=>5,self::OPTION_CONVERT_CHARSETS=>true,self::OPTION_VAR_CAST_REPLACE=>true,self::OPTION_DB_WRITE_CHANGES=>true,self::OPTION_HANDLE_SERIALIZE=>true,self::OPTION_REVERSED_FILTERS=>false,self::OPTION_LOCK_TABLES=>true,);protected $filters=array();protected $search=array();protected $replace=array();protected $search_converted=array();public function __construct(PDO$pdo){if(!extension_loaded('pcre')){throw new RuntimeException('The pcre (Perl-compatible regular expressions) extension is required for DBSR to work!');}if($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)!='mysql'){throw new InvalidArgumentException('The given PDO instance is not representing an MySQL database!');}$this->pdo=$pdo;}public function getOption($option){return isset($this->options[$option])?$this->options[$option]:null;}public function setOption($option,$value){if(!isset($this->options[$option])){return false;}switch($option){case static ::OPTION_SEARCH_PAGE_SIZE:if(is_int($value)&&$value>0){$this->options[$option]=$value;return true;}else{return false;}case static ::OPTION_FLOATS_PRECISION:if(is_int($value)&&$value>=0){$this->options[$option]=$value;return true;}else{return false;}default:if(gettype($this->options[$option])==gettype($value)){$this->options[$option]=$value;return true;}else{return false;}}}public function setFilters(array$filters){$filters_parsed=array();foreach($filters as $key=>$value){if(is_int($key)){if(is_string($value)){$filters_parsed[$value]=true;}elseif(is_array($value)){if(!count($value)){continue;}foreach($value as $v){if(!is_string($v)){throw new InvalidArgumentException('Only strings qualify as column names!');}}if(isset($filters_parsed['.'])){$filters_parsed['.']=array_values(array_unique(array_merge($filters_parsed['.'],array_values($value))));}else{$filters_parsed['.']=array_values(array_unique($value));}}else{throw new InvalidArgumentException('The filter array can only contain strings or arrays!');}}else{if(is_string($value)){if(isset($filters_parsed[$key])){$filters_parsed[$key]=array_values(array_unique(array_merge($filters_parsed[$key],array($value))));}else{$filters_parsed[$key]=array($value);}}elseif(is_array($value)){if(!count($value)){continue;}foreach($value as $v){if(!is_string($v)){throw new InvalidArgumentException('Only strings qualify as column names!');}}if(isset($filters_parsed[$key])){$filters_parsed[$key]=array_values(array_unique(array_merge($filters_parsed[$key],array_values($value))));}else{$filters_parsed[$key]=array_values(array_unique($value));}}else{throw new InvalidArgumentException('The filter array can only contain strings or arrays!');}}}$this->filters=$filters_parsed;}public function resetFilters(){$this->filters=array();}public function isFiltered($table,$column=null){if($this->getOption(static ::OPTION_REVERSED_FILTERS)){if($column==null){return false;}else{return!(isset($this->filters[$table])&&$this->filters[$table]===true||isset($this->filters[$table])&&in_array($column,$this->filters[$table],true)||isset($this->filters['.'])&&in_array($column,$this->filters['.'],true));}}else{if($column==null){return isset($this->filters[$table])&&$this->filters[$table]===true;}else{return isset($this->filters[$table])&&$this->filters[$table]===true||isset($this->filters[$table])&&in_array($column,$this->filters[$table],true)||isset($this->filters['.'])&&in_array($column,$this->filters['.'],true);}}}public function setValues(array$search,array$replace){if(count($search)==0||count($replace)==0||count($search)!=count($replace)){throw new InvalidArgumentException('The number of search- and replace-values is invalid!');}$search=array_values($search);$replace=array_values($replace);for($i=0;$i<count($search);$i++){if($search[$i]===$replace[$i]){array_splice($search,$i,1);array_splice($replace,$i,1);$i--;}}if(count($search)==0){throw new InvalidArgumentException('All given search- and replace-values are identical!');}$this->search=$search;$this->replace=$replace;}public function exec(){if(!ini_get('safe_mode')&&ini_get('max_execution_time')!='0'){set_time_limit(0);}return $this->DBRunner(array($this,'searchReplace'));}protected function DBRunner($callback){$this->_dbr_callback=$callback;$result=0;$unserialize_callback_func=ini_set('unserialize_callback_func',__CLASS__.'::createClass');$pdo_attributes=array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION);foreach($pdo_attributes as $attribute=>$value){$pdo_attributes[$attribute]=$this->pdo->getAttribute($attribute);$this->pdo->setAttribute($attribute,$value);}try{$this->_pdo_charset=$this->pdo->query('SELECT @@character_set_client;',PDO::FETCH_COLUMN,0)->fetch();$this->_pdo_collation=$this->pdo->query('SELECT @@collation_connection;',PDO::FETCH_COLUMN,0)->fetch();$tables=$this->pdo->query('SHOW TABLES;',PDO::FETCH_COLUMN,0)->fetchAll();if(count($tables)==0){throw new Exception('Database does not contain any tables.');}if($this->getOption(static ::OPTION_LOCK_TABLES)){$this->pdo->query('LOCK TABLES `'.implode('` WRITE, `',$tables).'` WRITE;');}foreach($tables as $table){if(!$this->isFiltered($table)){$result+=$this->_DBRTable($table,$callback);}}}catch(Exception$e){}if($this->getOption(static ::OPTION_LOCK_TABLES)){$this->pdo->query('UNLOCK TABLES');}foreach($pdo_attributes as $attribute=>$value){$this->pdo->setAttribute($attribute,$value);}ini_set('unserialize_callback_func',$unserialize_callback_func);if(isset($e)&&$e instanceof Exception){throw $e;}else{return $result;}}private function _DBRTable($table){$columns_info=$this->pdo->query('SHOW FULL COLUMNS FROM `'.$table.'`;',PDO::FETCH_NAMED);$columns=array();$keys=array();foreach($columns_info as $column_info){$columns[$column_info['Field']]=array('null'=>($column_info['Null']=='YES'),'type'=> static ::getPHPType($column_info['Type']),'charset'=>preg_replace('/^([a-z\d]+)_[\w\d]+$/i','$1',$column_info['Collation']),'collation'=>$column_info['Collation'],);$keys[$column_info['Key']][$column_info['Field']]=$columns[$column_info['Field']];}if(isset($keys['PRI'])){$keys=$keys['PRI'];}elseif(isset($keys['UNI'])){$keys=$keys['UNI'];}else{$keys=$columns;}foreach($columns as $column=>$column_info){if($this->isFiltered($table,$column)){unset($columns[$column]);}}if(!$this->getOption(static ::OPTION_EXTENSIVE_SEARCH)){$where=$this->_DBRWhereSearch($columns);}else{$where='';}if(count($columns)==0){return;}if($this->getOption(static ::OPTION_CONVERT_CHARSETS)){foreach($columns as $column=>$column_info){if(!isset($this->search_converted[$column_info['charset']])&&$column_info['type']=='string'&&!empty($column_info['charset'])&&$column_info['charset']!=$this->_pdo_charset){foreach($this->search as $i=>$item){if(is_string($item)){$this->search_converted[$column_info['charset']][$i]=$this->pdo->query('SELECT CONVERT(_'.$this->_pdo_charset.$this->pdo->quote($item).' USING '.$column_info['charset'].');',PDO::FETCH_COLUMN,0)->fetch();}else{$this->search_converted[$column_info['charset']][$i]=$item;}}}}}$row_count=(int)$this->pdo->query('SELECT COUNT(*) FROM `'.$table.'`'.$where.';',PDO::FETCH_COLUMN,0)->fetch();$row_change_count=0;$page_size=$this->getOption(static ::OPTION_SEARCH_PAGE_SIZE);for($page_start=0;$page_start<$row_count;$page_start+=$page_size){$rows=$this->pdo->query('SELECT * FROM `'.$table.'`'.$where.'LIMIT '.$page_start.', '.$page_size.';',PDO::FETCH_ASSOC);foreach($rows as $row){if($this->_DBRRow($table,$columns,$keys,$row)>0){$row_change_count++;}}}return $row_change_count;}private function _DBRRow($table,array$columns,array$keys,array$row){$changeset=array();foreach($columns+$keys as $column=>$column_info){if(!settype($row[$column],$column_info['type'])){throw new UnexpectedValueException('Failed to convert `'.$table.'`.`'.$column.'` value to a '.$column_info['type'].' for value "'.$row[$column].'"!');}}foreach($columns as $column=>$column_info){$value=&$row[$column];if($this->getOption(static ::OPTION_CONVERT_CHARSETS)&&isset($this->search_converted[$column_info['charset']])){$value_new=call_user_func($this->_dbr_callback,$value,$this->search_converted[$column_info['charset']],$this->replace);}else{$value_new=call_user_func($this->_dbr_callback,$value);}if($value_new!==$value){$changeset[$column]=$value_new;}}if(count($changeset)>0&&$this->getOption(static ::OPTION_DB_WRITE_CHANGES)){$where=$this->_DBRWhereRow($keys,$row);$updates=array();foreach($changeset as $column=>$value_new){switch($columns[$column]['type']){case 'integer':$updates[]='`'.$column.'` = '.(int)$value_new;break;case 'float':$updates[]='`'.$column.'` = '.(string)round((float)$value_new,$this->getOption(static ::OPTION_FLOATS_PRECISION));break;case 'string':default:$update_string=$this->pdo->quote((string)$value_new);if(!empty($columns[$column]['charset'])&&$this->_pdo_charset!=$columns[$column]['charset']){if($this->getOption(static ::OPTION_CONVERT_CHARSETS)){$update_string='CONVERT(_'.$this->_pdo_charset.$update_string.' USING '.$columns[$column]['charset'].')';}else{$update_string='BINARY '.$update_string;}}if(!empty($columns[$column]['collation'])&&$this->getOption(static ::OPTION_CONVERT_CHARSETS)&&$this->_pdo_collation!=$columns[$column]['collation']){$update_string.=' COLLATE '.$columns[$column]['collation'];}$updates[]='`'.$column.'` = '.$update_string;break;}}$this->pdo->query('UPDATE `'.$table.'` SET '.implode(', ',$updates).$where.';');}return count($changeset);}private function _DBRWhereSearch(array&$columns){$where=array();foreach($columns as $column=>$column_info){$where_column=false;foreach($this->search as $item){if($where_component=$this->_DBRWhereColumn($column,$column_info,$item,false)){$where[]=$where_component;$where_column=true;}}if(!$where_column){unset($columns[$column]);}}if(count($where)>0){return ' WHERE '.implode(' OR ',$where).' ';}else{if(count($columns)!=0){throw new LogicException('No WHERE-clause was constructed, yet there are valid columns left!');}return false;}}private function _DBRWhereRow(array$keys,array$row){$where=array();foreach($keys as $key=>$key_info){$where[]=$this->_DBRWhereColumn($key,$key_info,$row[$key],true);}return ' WHERE '.implode(' AND ',$where).' ';}private function _DBRWhereColumn($column,array$column_info,$value,$string_exact){switch($column_info['type']){case 'integer':if(!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)||is_int($value)){return '`'.$column.'` = '.(int)$value;}break;case 'float':if(!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)||is_float($value)){return 'ABS(`'.$column.'` - '.(float)$value.') < POW(1, -'.$this->getOption(static ::OPTION_FLOATS_PRECISION).')';}break;case 'string':default:if(is_float($value)){$value=round($value,$this->getOption(static ::OPTION_FLOATS_PRECISION));}if(!$string_exact){$value='%'.(string)$value.'%';}$where_string=$this->pdo->quote((string)$value);if(!empty($column_info['charset'])&&$this->_pdo_charset!=$column_info['charset']){if($this->getOption(static ::OPTION_CONVERT_CHARSETS)){$where_string='CONVERT(_'.$this->_pdo_charset.$where_string.' USING '.$column_info['charset'].')';}else{$where_string='BINARY '.$where_string;}}if(!empty($column_info['collation'])&&$this->getOption(static ::OPTION_CONVERT_CHARSETS)&&$this->_pdo_collation!=$column_info['collation']){if($this->getOption(static ::OPTION_CASE_INSENSITIVE)){$where_string.=' COLLATE '.preg_replace('/_cs$/i','_ci',$column_info['collation']);}else{$where_string.=' COLLATE '.$column_info['collation'];}}$column='`'.$column.'`';if(!empty($column_info['collation'])&&$this->getOption(static ::OPTION_CASE_INSENSITIVE)&&preg_replace('/^.*_([a-z]+)$/i','$1',$column_info['collation'])=='cs'){$column.=' COLLATE '.preg_replace('/_cs$/i','_ci',$column_info['collation']);}$where_string=$column.' '.($string_exact?'=':'LIKE').' '.$where_string;if(!empty($column_info['charset'])&&!$this->getOption(static ::OPTION_CONVERT_CHARSETS)&&$this->_pdo_charset!=$column_info['charset']){$where_string='BINARY '.$where_string;}return $where_string;}return false;}protected function searchReplace($value){$new_value=$value;switch(true){case is_array($value):$new_value=array();foreach($value as $key=>$element){$new_value[$this->searchReplace($key)]=$this->searchReplace($element);}break;case is_bool($value):for($i=0;$i<count($this->search);$i++){if($new_value===$this->search[$i]||!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)&&$new_value==$this->search[$i]){$new_value=$this->replace[$i];}}break;case is_float($value):$float_precision=pow(10,-1*$this->getOption(static ::OPTION_FLOATS_PRECISION));for($i=0;$i<count($this->search);$i++){if(is_float($this->search[$i])&&abs($new_value-$this->search[$i])<$float_precision||!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)&&($new_value==$this->search[$i]||abs($new_value-(float)$this->search[$i])<$float_precision)){$new_value=$this->replace[$i];}}break;case is_int($value):for($i=0;$i<count($this->search);$i++){if($new_value===$this->search[$i]||!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)&&$new_value==$this->search[$i]){$new_value=$this->replace[$i];}}break;case is_object($value):$new_value=unserialize($this->searchReplace(preg_replace('/^O:\\d+:/','O:0:',serialize($new_value))));break;case is_string($value):$serialized_regex='/^(?:a:\\d+:\\{.*\\}|b:[01];|d:\\d+\\.\\d+;|i:\\d+;|N;|O:\\d+:"[a-zA-Z_\\x7F-\\xFF][a-zA-Z0-9_\\x7F-\\xFF]*(?:\\\\[a-zA-Z_\\x7F-\\xFF][a-zA-Z0-9_\\x7F-\\xFF]*)*":\\d+:\\{.*\\}|s:\\d+:".*";)$/Ss';$unserialized=@unserialize($new_value);if($this->getOption(static ::OPTION_HANDLE_SERIALIZE)&&($unserialized!==false||$new_value===serialize(false))&&!is_object($unserialized)){$new_value=serialize($this->searchReplace($unserialized));}elseif($this->getOption(static ::OPTION_HANDLE_SERIALIZE)&&(is_object($unserialized)||preg_match($serialized_regex,$new_value))){if($changed_value=preg_replace_callback('/b:([01]);/S',array($this,'_searchReplace_preg_callback_boolean'),$new_value)){$new_value=$changed_value;}if($changed_value=preg_replace_callback('/i:(\\d+);/S',array($this,'_searchReplace_preg_callback_integer'),$new_value)){$new_value=$changed_value;}if($changed_value=preg_replace_callback('/d:(\\d+)\.(\\d+);/S',array($this,'_searchReplace_preg_callback_float'),$new_value)){$new_value=$changed_value;}if($changed_value=preg_replace_callback('/O:\\d+:"([a-zA-Z_\\x7F-\\xFF][a-zA-Z0-9_\\x7F-\\xFF]*(?:\\\\[a-zA-Z_\\x7F-\\xFF][a-zA-Z0-9_\\x7F-\\xFF]*)*)":(\\d+):{(.*)}/Ss',array($this,'_searchReplace_preg_callback_objectname'),$new_value)){$new_value=$changed_value;}if($changed_value=preg_replace_callback('/s:\\d+:"(.*?|a:\\d+:{.*}|b:[01];|d:\\d+\\.\\d+;|i:\d+;|N;|O:\\d+:"[a-zA-Z_\\x7F-\\xFF][a-zA-Z0-9_\\x7F-\\xFF]*":\\d+:{.*}|s:\\d+:".*";)";/Ss',array($this,'_searchReplace_preg_callback_string'),$new_value)){$new_value=$changed_value;}if($new_value==$value){for($i=0;$i<count($this->search);$i++){if(is_string($this->search[$i])||!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)){$new_value=$this->getOption(static ::OPTION_CASE_INSENSITIVE)?str_ireplace((string)$this->search[$i],(string)$this->replace[$i],$new_value):str_replace((string)$this->search[$i],(string)$this->replace[$i],$new_value);}}}}else{for($i=0;$i<count($this->search);$i++){if(is_string($this->search[$i])||!$this->getOption(static ::OPTION_VAR_MATCH_STRICT)){$new_value=$this->getOption(static ::OPTION_CASE_INSENSITIVE)?str_ireplace((string)$this->search[$i],(string)$this->replace[$i],$new_value):str_replace((string)$this->search[$i],(string)$this->replace[$i],$new_value);}}}break;}return $new_value;}private function _searchReplace_preg_callback_boolean($matches){$result=$this->searchReplace((boolean)$matches[1]);if(static ::OPTION_VAR_CAST_REPLACE){$result=(boolean)$result;}return serialize($result);}private function _searchReplace_preg_callback_integer($matches){$result=$this->searchReplace((integer)$matches[1]);if(static ::OPTION_VAR_CAST_REPLACE){$result=(integer)$result;}return serialize($result);}private function _searchReplace_preg_callback_float($matches){$result=$this->searchReplace((float)($matches[1].'.'.$matches[2]));if(static ::OPTION_VAR_CAST_REPLACE){$result=(float)$result;}return serialize($result);}private function _searchReplace_preg_callback_objectname($matches){$name=preg_replace('/[^a-zA-Z0-9_\\x7F-\\xFF\\\\]+/','',(string)$this->searchReplace($matches[1]));return 'O:'.strlen($name).':"'.$name.'":'.$matches[2].':{'.$matches[3].'}';}private function _searchReplace_preg_callback_string($matches){$result=$this->searchReplace($matches[1]);if(static ::OPTION_VAR_CAST_REPLACE){$result=(string)$result;}return serialize($result);}}class DBSR_CLI{protected static $default_options=array('CLI'=>array('help'=>array('name'=>array('help','h','?'),'parameter'=>null,'description'=>'display this help and exit','default_value'=>null,),'version'=>array('name'=>array('version','v'),'parameter'=>null,'description'=>'print version information and exit','default_value'=>null,),'file'=>array('name'=>array('file','configfile','config','f'),'parameter'=>'FILENAME','description'=>'JSON-encoded config file to load','default_value'=>null,),'output'=>array('name'=>array('output','o'),'parameter'=>'text|json','description'=>'output format','default_value'=>'text',),),'PDO'=>array('host'=>array('name'=>array('host','hostname'),'parameter'=>'HOSTNAME','description'=>'hostname of the MySQL server','default_value'=>null,),'port'=>array('name'=>array('port','portnumber'),'parameter'=>'PORTNUMBER','description'=>'port number of the MySQL server','default_value'=>null,),'user'=>array('name'=>array('user','username','u'),'parameter'=>'USERNAME','description'=>'username used for connecting to the MySQL server','default_value'=>null,),'password'=>array('name'=>array('password','pass','p'),'parameter'=>'PASSWORD','description'=>'password used for connecting to the MySQL server','default_value'=>null,),'database'=>array('name'=>array('database','db','d'),'parameter'=>'DATABASE','description'=>'name of the database to be searched','default_value'=>null,),'charset'=>array('name'=>array('charset','characterset','char'),'parameter'=>'CHARSET','description'=>'character set used for connecting to the MySQL server','default_value'=>null,),),'DBSR'=>array(DBSR::OPTION_CASE_INSENSITIVE=>array('name'=>'case-insensitive','parameter'=>'[true|false]','description'=>'use case-insensitive search and replace','default_value'=>false,),DBSR::OPTION_EXTENSIVE_SEARCH=>array('name'=>'extensive-search','parameter'=>'[true|false]','description'=>'process *all* database rows','default_value'=>false,),DBSR::OPTION_SEARCH_PAGE_SIZE=>array('name'=>'search-page-size','parameter'=>'SIZE','description'=>'number of rows to process simultaneously','default_value'=>10000,),DBSR::OPTION_VAR_MATCH_STRICT=>array('name'=>'var-match-strict','parameter'=>'[true|false]','description'=>'use strict matching','default_value'=>true,),DBSR::OPTION_FLOATS_PRECISION=>array('name'=>'floats-precision','parameter'=>'PRECISION','description'=>'up to how many decimals floats should be matched','default_value'=>5,),DBSR::OPTION_CONVERT_CHARSETS=>array('name'=>'convert-charsets','parameter'=>'[true|false]','description'=>'automatically convert character sets','default_value'=>true,),DBSR::OPTION_VAR_CAST_REPLACE=>array('name'=>'var-cast-replace','parameter'=>'[true|false]','description'=>'cast all replace-values to the original type','default_value'=>true,),DBSR::OPTION_DB_WRITE_CHANGES=>array('name'=>'db-write-changes','parameter'=>'[true|false]','description'=>'write changed values back to the database','default_value'=>true,),DBSR::OPTION_HANDLE_SERIALIZE=>array('name'=>'handle-serialize','parameter'=>'[true|false]','description'=>'interpret serialized strings as their PHP types','default_value'=>true,),DBSR::OPTION_LOCK_TABLES=>array('name'=>'lock-tables','parameter'=>'[true|false]','description'=>'lock tables when running','default_value'=>true,),),);public static function printVersion(){echo 'DBSR '.DBSR::VERSION.' CLI, running on PHP ',PHP_VERSION,' (',\PHP_SAPI,'), ',PHP_OS,'.',"\n";}public static function printHelp($filename=null){$pad_left=4;$width_left=40;$width_right=32;if(null===$filename){if(isset($_SERVER['argv'])&&is_array($_SERVER['argv'])){$filename=$_SERVER['argv'][0];}else{$filename=basename($_SERVER['SCRIPT_NAME']);}}static ::printVersion();echo "\n",'Usage: ',$filename,' [options] -- SEARCH REPLACE [SEARCH REPLACE...]',"\n".' ',$filename,' --file FILENAME',"\n"."\n";foreach(static ::$default_options as $name=>$optionset){echo $name,' options:',"\n";foreach($optionset as $option){$option['name']=(array)$option['name'];$parameter=(strlen($option['name'][0])>1?'--':'-').$option['name'][0];if(null!==$option['parameter']){$parameter.=' '.$option['parameter'];}$description_array=preg_split('/(.{1,'.$width_right.'}(?:\s(?!$)|(?=$)))/',$option['description'],null,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);$description=$description_array[0];for($i=1;$i<count($description_array);$i++){$description.="\n".str_repeat(' ',$width_left+$pad_left).$description_array[$i];}if(null!==$option['default_value']){$default=$option['default_value'];if(is_bool($default)){$default=$default?'true':'false';}else{$default=(string)$default;}$default=' (default: '.$default.')';if(strlen($description_array[count($description_array)-1])+strlen($default)>$width_right){$description.="\n".str_repeat(' ',$width_left+$pad_left-1);}$description.=$default;}echo str_repeat(' ',$pad_left),str_pad($parameter,$width_left),$description,"\n";}}}protected static function getOption($switch,$check_prefix=true){foreach(static ::$default_options as $setname=>$set){foreach($set as $id=>$option){foreach((array)$option['name']as $name){if($switch==($check_prefix?(strlen($name)>1?('--'.$name):('-'.$name)):$name)){$option['set']=$setname;$option['id']=$id;return $option;}}}}return false;}protected $pdo;protected $dbsr;protected $options=array();protected $search=array();protected $replace=array();private $configfiles=array();public function __construct(){foreach(static ::$default_options as $setname=>$set){foreach($set as $id=>$option){if(null!==$option['default_value']){$this->options[$setname][$id]=$option['default_value'];}}}}public function exec(){$pdo_options=array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,);$dsn='mysql:';if(isset($this->options['PDO']['host'])){$dsn.='host='.$this->options['PDO']['host'];if(isset($this->options['PDO']['port'])){$dsn.=':'.$this->options['PDO']['port'];}$dsn.=';';}if(isset($this->options['PDO']['database'])){$dsn.='dbname='.$this->options['PDO']['database'].';';}if(isset($this->options['PDO']['charset'])){$pdo_options[PDO::MYSQL_ATTR_INIT_COMMAND]='SET NAMES '.$this->options['PDO']['charset'];$dsn.='charset='.$this->options['PDO']['charset'].';';}try{$this->pdo=new PDO($dsn,@$this->options['PDO']['user'],@$this->options['PDO']['password'],$pdo_options);$this->dbsr=new DBSR($this->pdo);foreach($this->options['DBSR']as $option=>$value){$this->dbsr->setOption($option,$value);}$this->dbsr->setValues($this->search,$this->replace);$result=$this->dbsr->exec();}catch(Exception$e){switch($this->options['CLI']['output']){case 'json':exit(json_encode(array('error'=>$e->getMessage())));case 'text':default:exit($e->getMessage());}}switch($this->options['CLI']['output']){case 'text':exit('Result: '.$result.' rows were '.($this->options['DBSR'][DBSR::OPTION_DB_WRITE_CHANGES]?'changed':'matched (no changes were written to the databasse)').'!');case 'json':exit(json_encode(array('result'=>$result)));}}public function parseArguments(array$arguments){if(empty($arguments)){if(isset($_SERVER['argv'])&&is_array($_SERVER['argv'])){$arguments=$_SERVER['argv'];}else{$arguments=array(basename($_SERVER['SCRIPT_NAME']));}}if(count($arguments)<=1){echo 'Usage: ',$arguments[0],' [options] -- SEARCH REPLACE [SEARCH REPLACE...]',"\n".' ',$arguments[0],' --file FILENAME',"\n".'Try `',$arguments[0],' --help` for more information.',"\n";exit;}for($i=1;$i<count($arguments);$i++){switch($arguments[$i]){case '--':if(count($arguments)-1-$i==0){exit('Missing search- and replace-values!');}if((count($arguments)-1-$i)%2!=0){exit('Missing replace-value for seach-value: '.(string)$arguments[count($arguments)-1]);}for(++$i;$i<count($arguments);$i++){$this->search[]=$arguments[$i];$this->replace[]=$arguments[++$i];}break;default:$option=static ::getOption($arguments[$i]);if(!$option){exit('Unknown argument: '.(string)$arguments[$i]);}if(null!==$option['parameter']){$arg=@$arguments[$i+1];if(is_bool($option['default_value'])&&(null===$arg||preg_match('/^\-/',$arg))){$this->options[$option['set']][$option['id']]=!$option['default_value'];break;}if(null===$arg||preg_match('/^\-/',$arg)){exit('Missing option for '.(string)$arguments[$i]);}switch($option['set'].'/'.$option['id']){case 'CLI/output':if($arg=='json'&&!extension_loaded('json')){exit('Error: The PHP JSON extension is not available!');}break;case 'CLI/file':if(!extension_loaded('json')){exit('Error: The PHP JSON extension is not available!');}if(!$this->parseConfig($arg)){exit('Failed to parse config file: '.(string)$arg);}$i++;break 2;}if(null!==$option['default_value']){if(is_bool($option['default_value'])){if(strtolower($arg)=='true'){$arg=true;}elseif(strtolower($arg)=='false'){$arg=false;}elseif(is_numeric($arg)){$arg=(bool)(int)$arg;}else{exit('Invalid argument, expected boolean for '.(string)$arguments[$i]);}}elseif(is_int()){if(is_numeric($arg)){$arg=(int)$arg;}else{exit('Invalid argument, expected integer for '.(string)$arguments[$i]);}}elseif(is_float()){if(is_numeric($arg)){$arg=(float)$arg;}else{exit('Invalid argument, expected float for '.(string)$arguments[$i]);}}settype($arg,gettype($option['default_value']));}$this->options[$option['set']][$option['id']]=$arg;$i++;}else{switch($option['set'].'/'.$option['id']){case 'CLI/help':exit(static ::printHelp($arguments[0]));case 'CLI/version':exit(static ::printVersion());}}break;}}}public function parseConfig($file){if(!file_exists($file)||!realpath($file)){return false;}if(in_array(realpath($file),$this->configfiles)){return false;}$this->configfiles[]=realpath($file);$file_contents=@file_get_contents($file);if(!$file_contents){return false;}$file_array=json_decode($file_contents,true);if(!is_array($file_array)){return false;}if(isset($file_array['search'])&&is_array($file_array['search'])){$this->search+=$file_array['search'];}if(isset($file_array['replace'])&&is_array($file_array['replace'])){$this->replace+=$file_array['replace'];}if(isset($file_array['options'])&&is_array($file_array['options'])){return $this->_parseConfigArray($file_array['options']);}else{return true;}}private function _parseConfigArray(array$array){foreach($array as $key=>$element){if(is_array($element)){if(!$this->_parseConfigArray($element)){return false;}}else{$option=static ::getOption($key,false);if(!$option){return false;}switch($option['set'].'/'.$option['id']){case 'CLI/help':exit(static ::printHelp());case 'CLI/version':exit(static ::printVersion());}if(null===$option['parameter']){return false;}switch($option['set'].'/'.$option['id']){case 'CLI/file':if(!$this->parseConfig($element)){return false;}}$this->options[$option['set']][$option['id']]=$element;}}return true;}}class Bootstrapper{private static $is_initialized=false;public static function exception_error_handler($errno,$errstr,$errfile,$errline){if(($errno&error_reporting())!=0){throw new ErrorException($errstr,0,$errno,$errfile,$errline);}}public static function autoloader($class_name){if(class_exists($class_name)){return true;}$include_paths=explode(PATH_SEPARATOR,get_include_path());foreach($include_paths as $include_path){if(empty($include_path)||!is_dir($include_path)){continue;}$include_path=rtrim($include_path,'\\/'.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;foreach(array('.php','.php5','.inc.php','.inc.php5','.inc')as $extension){$count=substr_count($class_name,'_');for($i=0;$i<=$count;$i++){$filename=$include_path.preg_replace('/_/',\DIRECTORY_SEPARATOR,$class_name,$i).$extension;if(is_readable($filename)){include_once $filename;if(class_exists($class_name)){return true;}}}}}return false;}protected static function stripslashes_recursive($value){return is_array($value)?array_map(array(__CLASS__,'stripslashes_recursive'),$value):(is_string($value)?stripslashes($value):$value);}public static function initialize(){if(static ::$is_initialized){return;}set_error_handler(array(__CLASS__,'exception_error_handler'));if(!defined('DEBUG')){define('DEBUG',false);}error_reporting(DEBUG?E_ALL:0);set_include_path(get_include_path().PATH_SEPARATOR.realpath(__DIR__));spl_autoload_register(array(__CLASS__,'autoloader'));if(function_exists('get_magic_quotes_gpc')&&@get_magic_quotes_gpc()){$_POST=static ::stripslashes_recursive($_POST);$_GET=static ::stripslashes_recursive($_GET);$_COOKIE=static ::stripslashes_recursive($_COOKIE);$_REQUEST=static ::stripslashes_recursive($_REQUEST);@ini_set('magic_quotes_gpc',false);}if(function_exists('set_magic_quotes_runtime')){@set_magic_quotes_runtime(false);}@ini_set('memory_limit','-1');@ini_set('pcre.recursion_limit','100');@ini_set('default_charset','UTF-8');if(extension_loaded('mbstring')){@mb_internal_encoding('UTF-8');}if(version_compare(PHP_VERSION,'5.6','<')&&extension_loaded('iconv')){@iconv_set_encoding('internal_encoding','UTF-8');}date_default_timezone_set('UTC');static ::$is_initialized=true;}public static function sessionDestroy(){$_SESSION=array();session_destroy();session_commit();}public static function sessionStart(){$security_data=array('server_ip'=>@$_SERVER['SERVER_ADDR'],'server_file'=>__FILE__,'client_ip'=>$_SERVER['REMOTE_ADDR'],'client_ua'=>$_SERVER['HTTP_USER_AGENT']);@ini_set('sessions.gc_maxlifetime',(string)(60*60*24));session_name('DBSR_session');session_start();if(session_id()==''||!isset($_SESSION['_session_security_data'])){$_SESSION['_session_security_data']=$security_data;}else{if($_SESSION['_session_security_data']!==$security_data){static ::sessionDestroy();static ::sessionStart();}}}}Bootstrapper::initialize();if(\PHP_SAPI!='cli'&&!empty($_SERVER['REMOTE_ADDR'])){$_SERVER['argv']=array(basename($_SERVER['SCRIPT_FILENAME']));if(isset($_GET['args'])&&strlen(trim($_GET['args']))>0){$_SERVER['argv']=array_merge($_SERVER['argv'],explode(' ',trim($_GET['args'])));}@ini_set('html_errors',0);function DBSR_CLI_output($output){header('Content-Type: text/html; charset=UTF-8');return '<!DOCTYPE html>'."\n".'<html lang="en">'."\n".'<head>'."\n"."\t".'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'."\n"."\t".'<title>DBSR CLI</title>'."\n".'</head>'."\n".'<body>'."\n"."\t".'<form action="'.@$_SERVER['argv'][0].'" method="get">'."\n"."\t\t".'<p>'.htmlspecialchars(@$_SERVER['argv'][0]).' <input type="text" name="args" value="'.htmlspecialchars(@$_GET['args']).'" size="100" autofocus="autofocus"/></p>'."\n"."\t".'</form>'."\n"."\t".'<pre>'.htmlspecialchars($output).'</pre>'."\n".'</body>'."\n".'</html>';}ob_start('DBSR_CLI_output');}$cli=new DBSR_CLI();$cli->parseArguments($_SERVER['argv']);$cli->exec();exit;