ActionApps PHP Cross Reference Groupware Applications

Source: /include/optimize.class.php3 - 1145 lines - 46869 bytes - Summary - Text - Print

Description: PHP versions 4 and 5

   1  <?php
   2   /**
   3   *
   4   * PHP versions 4 and 5
   5   *
   6   * LICENSE: This program is free software; you can redistribute it and/or modify
   7   * it under the terms of the GNU General Public License as published by
   8   * the Free Software Foundation; either version 2 of the License, or
   9   * (at your option) any later version.
  10   *
  11   * This program is distributed in the hope that it will be useful,
  12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14   * GNU General Public License for more details.
  15   *
  16   * You should have received a copy of the GNU General Public License
  17   * along with this program (LICENSE); if not, write to the Free Software
  18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19   *
  20   * @package   Maintain
  21   * @version   $Id: se_csv_import.php3 2290 2006-07-27 15:10:35Z honzam $
  22   * @author    Honza Malik <honza.malik@ecn.cz>
  23   * @license   http://opensource.org/licenses/gpl-license.php GNU Public License
  24   * @copyright Copyright (C) 1999, 2000 Association for Progressive Communications
  25   * @link      http://www.apc.org/ APC
  26  */
  27  
  28  require_once  AA_BASE_PATH."service/update.optimize.class.php";
  29  
  30  /** Testing if relation table contain records, where values in both columns are
  31   *  identical (which was bug fixed in Jan 2006)
  32   */
  33  class AA_Optimize_Category_Sort2group_By extends AA_Optimize {
  34  
  35      /** Name function
  36      * @return a message
  37      */
  38      function name() {
  39          return _m("Convert slice.category_sort to slice.group_by");
  40      }
  41  
  42      /** Description function
  43      * @return a message
  44      */
  45      function description() {
  46          return _m("In older version of AA we used just category fields for grouping items. Now it is universal, so boolean category_sort is not enough. We use newer group_by field for quite long time s most probably all your slices are already conevrted.");
  47      }
  48  
  49      /** Test function
  50      * @return bool
  51      */
  52      function test() {
  53          $SQL         = "SELECT name FROM slice WHERE category_sort>0 AND ((group_by IS NULL) OR (group_by=''))";
  54          $slice_names = GetTable2Array($SQL, '', 'name');
  55          if ($slice_names AND (count($slice_names) > 0)) {
  56              $this->message( _m('%1 slices are not converted', array(count($slice_names))). '<br> &nbsp; '. join('<br> &nbsp; ',$slice_names));
  57              return false;
  58          }
  59          $this->message(_m('All slices are already converted'));
  60          return true;
  61      }
  62  
  63      /** Repair function
  64      * runs a series of SQL commands
  65      * @return bool
  66      */
  67      function repair() {
  68          $db     = getDb();
  69          $SQL    = "SELECT id FROM slice WHERE category_sort>0 AND ((group_by IS NULL) OR (group_by=''))";
  70          $slices = GetTable2Array($SQL, '', 'id');
  71          foreach ($slices as $p_slice_id) {
  72              $q_slice_id = quote($p_slice_id);
  73              $SQL        = "SELECT id FROM field WHERE id LIKE 'category.......%' AND slice_id='$q_slice_id'";
  74              $cat_field  = GetTable2Array($SQL, "aa_first", 'id');
  75              if ($cat_field) {
  76                  // number 2 represents 'a' - ascending (because gb_direction in number)
  77                  $SQL = "UPDATE slice SET group_by='". quote($cat_field) ."', gb_direction=2, gb_header=0 WHERE id='$q_slice_id'";
  78              } else {
  79                  $SQL = "UPDATE slice SET group_by='', gb_direction=0, gb_header=0 WHERE id='$q_slice_id'";
  80              }
  81              $db->query($SQL);   // correct it
  82          }
  83          // fix all category_sort
  84          $SQL = "UPDATE slice SET category_sort=0";
  85          $db->query($SQL);
  86          freeDb($db);
  87          return true;
  88      }
  89  }
  90  
  91  
  92  /** Generate metabase definition row */
  93  class AA_Optimize_Generate_Metabase extends AA_Optimize {
  94  
  95      /** Name function
  96      * @return a message
  97      */
  98      function name() {
  99          return _m("Generate metabase definition row");
 100      }
 101  
 102      /** Description function
 103      * @return a message
 104      */
 105      function description() {
 106          return _m("For programmers only - Generate metabace definition row from current database bo be placed in /service/metabase.class.php3 and /include/metabase.class.php3 scripts");
 107      }
 108  
 109      /** implemented actions within this class */
 110      function actions()      { return array('repair'); }
 111  
 112      /** Name function
 113      * @return bool
 114      */
 115      function repair() {
 116          $metabase  = new AA_Metabase;
 117          $metabase->loadFromDb();
 118          echo '$instance = unserialize(\''. str_replace("'", '\\\'', serialize($metabase)) .'\');';
 119          exit;
 120      }
 121  }
 122  
 123  
 124  /** Testing if relation table contain records, where values in both columns are
 125   *  identical (which was bug fixed in Jan 2006)
 126   */
 127  class AA_Optimize_Db_Relation_Dups extends AA_Optimize {
 128  
 129      /** Name function
 130      * @return a message
 131      */
 132      function name() {
 133          return _m("Relation table duplicate records");
 134      }
 135  
 136      /** Description function
 137      * @return a message
 138      */
 139      function description() {
 140          return _m("Testing if relation table contain records, where values in both columns are identical (which was bug fixed in Jan 2006)");
 141      }
 142  
 143      /** Test function
 144      * tests for duplicate entries
 145      * @return bool
 146      */
 147      function test() {
 148          $SQL       = 'SELECT count(*) as err_count FROM `relation` WHERE `source_id`=`destination_id`';
 149          $err_count = GetTable2Array($SQL, "aa_first", 'err_count');
 150          if ($err_count > 0) {
 151              $this->message( _m('%1 duplicates found', array($err_count)) );
 152              return false;
 153          }
 154          $this->message(_m('No duplicates found'));
 155          return true;
 156      }
 157  
 158      /** Name function
 159      * @return bool
 160      */
 161      function repair() {
 162          $db  = getDb();
 163          $SQL = 'DELETE FROM `relation` WHERE `source_id`=`destination_id`';
 164          $db->query($SQL);
 165          freeDb($db);
 166          return true;
 167      }
 168  }
 169  
 170  
 171  /** Testing if feeds table do not contain relations to non existant slices
 172   */
 173  class AA_Optimize_Db_Feed_Inconsistency extends AA_Optimize {
 174  
 175      /** Name function
 176      * @return a message
 177      */
 178      function name() {
 179          return _m("Feeds table inconsistent records");
 180      }
 181  
 182      /** Description function
 183      * @return a message
 184      */
 185      function description() {
 186          return _m("Testing if feeds table do not contain relations to non existant slices (after slice deletion)");
 187      }
 188  
 189      /** Test function
 190      * tests for duplicate entries
 191      * @return bool
 192      */
 193      function test() {
 194          $ret = true;
 195  
 196          // test wrong destination slices
 197          $SQL = "SELECT from_id,to_id FROM feeds LEFT JOIN slice ON feeds.to_id=slice.id
 198                  WHERE slice.id IS NULL";
 199          $err = GetTable2Array($SQL, "unpack:from_id", 'unpack:to_id');
 200          if (is_array($err) AND count($err) > 0) {
 201              foreach ($err as $from_id => $to_id) {
 202                  $this->message( _m('Wrong destination slice id: %1 -> %2', array(AA_Slices::getName($from_id), $to_id)));
 203              }
 204              $ret = false;
 205          }
 206  
 207          // test wrong source slices
 208          $SQL = "SELECT from_id,to_id FROM feeds LEFT JOIN slice ON feeds.from_id=slice.id
 209                  WHERE slice.id IS NULL";
 210          $err = GetTable2Array($SQL, "unpack:from_id", 'unpack:to_id');
 211          if (is_array($err) AND count($err) > 0) {
 212              foreach ($err as $from_id => $to_id) {
 213                  $this->message( _m('Wrong source slice id: %1 -> %2', array($from_id, AA_Slices::getName($to_id))));
 214              }
 215              $ret = false;
 216          }
 217          if ($ret ) {
 218              $this->message(_m('No wrong references found, hurray!'));
 219          }
 220          return $ret;
 221      }
 222  
 223      /** Name function
 224      * @return bool
 225      */
 226      function repair() {
 227          $db  = getDb();
 228  
 229          // test wrong destination slices
 230          $SQL = "SELECT to_id FROM feeds LEFT JOIN slice ON feeds.to_id=slice.id WHERE slice.id IS NULL";
 231          $err = GetTable2Array($SQL, '', 'unpack:to_id');
 232  
 233          if (is_array($err) AND count($err)>0 ) {
 234              foreach ($err as $wrong_slice_id) {
 235                  $SQL = 'DELETE FROM `feeds` WHERE `to_id`=\''.q_pack_id($wrong_slice_id).'\'';
 236                  $db->query($SQL);
 237              }
 238          }
 239  
 240          // test wrong source slices
 241          $SQL = "SELECT from_id FROM feeds LEFT JOIN slice ON feeds.from_id=slice.id WHERE slice.id IS NULL";
 242          $err = GetTable2Array($SQL, '', 'unpack:from_id');
 243  
 244          if (is_array($err) AND count($err)>0 ) {
 245              foreach ($err as $wrong_slice_id) {
 246                  $SQL = 'DELETE FROM `feeds` WHERE `from_id`=\''.q_pack_id($wrong_slice_id).'\'';
 247                  $db->query($SQL);
 248              }
 249          }
 250  
 251          freeDb($db);
 252          return true;
 253      }
 254  }
 255  
 256  
 257  /** Testing if feeds table do not contain relations to non existant slices
 258   */
 259  class AA_Optimize_Db_Inconsistency extends AA_Optimize {
 260  
 261      /** Name function
 262      * @return a message
 263      */
 264      function name() {
 265          return _m("Check database consistency");
 266      }
 267  
 268      /** Description function
 269      * @return a message
 270      */
 271      function description() {
 272          return _m("Test content table for records without item table reference, test discussion for the same, ...");
 273      }
 274  
 275      /** Test function
 276      * tests for duplicate entries
 277      * @return bool
 278      */
 279      function test() {
 280          $ret = true;
 281  
 282  
 283          // test wrong destination slices
 284          $SQL = "SELECT slice_id FROM item LEFT JOIN slice ON item.slice_id=slice.id WHERE slice.id IS NULL";
 285          $err = GetTable2Array($SQL, '', "unpack:slice_id");
 286          if (is_array($err) AND count($err) > 0) {
 287              foreach ($err as $s_id) {
 288                  $this->message( _m('Wrong slice id in item table: %1', array($s_id)));
 289              }
 290              $ret = false;
 291          }
 292  
 293          // test wrong destination slices
 294          $SQL = "SELECT item_id, text FROM content LEFT JOIN item ON content.item_id=item.id WHERE item.id IS NULL";
 295          $err = GetTable2Array($SQL, "unpack:item_id", 'text');
 296          if (is_array($err) AND count($err) > 0) {
 297              foreach ($err as $item_id => $text) {
 298                  $this->message( _m('Wrong item id in content table: %1 -> %2', array($item_id, $text)));
 299              }
 300              $ret = false;
 301          }
 302  
 303          // test wrong source slices
 304          $SQL = "SELECT item_id, subject FROM discussion LEFT JOIN item ON discussion.item_id=item.id WHERE item.id IS NULL";
 305          $err = GetTable2Array($SQL, "unpack:item_id", 'subject');
 306          if (is_array($err) AND count($err) > 0) {
 307              foreach ($err as $item_id => $text) {
 308                  $this->message( _m('Wrong item id in discussion table: %1 -> %2', array($item_id, $text)));
 309              }
 310              $ret = false;
 311          }
 312          if ($ret ) {
 313              $this->message(_m('No wrong references found, hurray!'));
 314          }
 315          return $ret;
 316      }
 317  
 318      /** Name function
 319      * @return bool
 320      */
 321      function repair() {
 322          $db  = getDb();
 323  
 324          // test wrong content records
 325          $SQL = "SELECT slice_id FROM item LEFT JOIN slice ON item.slice_id=slice.id WHERE slice.id IS NULL";
 326          $err = GetTable2Array($SQL, '', "unpack:slice_id");
 327          if (is_array($err) AND count($err) > 0) {
 328              foreach ($err as $s_id) {
 329                  $SQL = 'DELETE FROM `item` WHERE `slice_id`=\''.q_pack_id($s_id).'\'';
 330                  $db->query($SQL);
 331                  $this->message( _m('Data for slice id %1 in item table deleted', array($s_id)));
 332              }
 333          }
 334  
 335          // test wrong content records
 336          $SQL = "SELECT item_id FROM content LEFT JOIN item ON content.item_id=item.id WHERE item.id IS NULL";
 337          $err = GetTable2Array($SQL, "", 'unpack:item_id');
 338          if (is_array($err) AND count($err) > 0) {
 339              foreach ($err as $item_id) {
 340                  $SQL = 'DELETE FROM `content` WHERE `item_id`=\''.q_pack_id($item_id).'\'';
 341                  $db->query($SQL);
 342                  $this->message( _m('Data for item id %1 in content table deleted', array($item_id)));
 343              }
 344          }
 345  
 346          // test wrong source slices
 347          $SQL = "SELECT item_id FROM discussion LEFT JOIN item ON discussion.item_id=item.id WHERE item.id IS NULL";
 348          $err = GetTable2Array($SQL, '', "unpack:item_id");
 349          if (is_array($err) AND count($err) > 0) {
 350              foreach ($err as $item_id) {
 351                  $SQL = 'DELETE FROM `discussion` WHERE `item_id`=\''.q_pack_id($item_id).'\'';
 352                  $db->query($SQL);
 353                  $this->message( _m('Data for item id %1 in discussion table deleted', array($item_id)));
 354              }
 355          }
 356  
 357          freeDb($db);
 358          return true;
 359      }
 360  }
 361  
 362  
 363  /** Fix user login problem, constants editiong problem, ...
 364   *  Replaces binary fields by varbinary and removes trailing zeros
 365   *  Needed for MySQL > 5.0.17
 366   */
 367  class AA_Optimize_Db_Binary_Traing_Zeros extends AA_Optimize {
 368  
 369      /** Name function
 370      * @return a message
 371      */
 372      function name() {
 373          return _m("Fix user login problem, constants editiong problem, ...");
 374      }
 375  
 376      /** Description function
 377      * @return a message
 378      */
 379      function description() {
 380          return _m("Replaces binary fields by varbinary and removes trailing zeros. Needed for MySQL > 5.0.17");
 381      }
 382  
 383      /** implemented actions within this class */
 384      function actions()      { return array('repair'); }
 385  
 386      /** Test function
 387      * @return true
 388      */
 389      function test() {
 390          return true;
 391      }
 392  
 393      /** Repair function
 394      * repairs tables
 395      * @return true
 396      */
 397      function repair() {
 398          $this->_fixTable('active_sessions','sid',"varbinary(32) NOT NULL default ''");
 399          $this->_fixTable('change','id',"varbinary(32) NOT NULL default ''");
 400          $this->_fixTable('change','resource_id',"varbinary(32) NOT NULL default ''");
 401          $this->_fixTable('change_record','change_id',"varbinary(32) NOT NULL default ''");
 402          $this->_fixTable('change_record','selector',"varbinary(255) default NULL");
 403          $this->_fixTable('central_conf','dns_conf',"varbinary(255) NOT NULL default ''");
 404          $this->_fixTable('central_conf','dns_web',"varbinary(15) NOT NULL default ''");
 405          $this->_fixTable('central_conf','dns_mx',"varbinary(15) NOT NULL default ''");
 406          $this->_fixTable('central_conf','dns_db',"varbinary(15) NOT NULL default ''");
 407          $this->_fixTable('central_conf','dns_prim',"varbinary(255) NOT NULL default ''");
 408          $this->_fixTable('central_conf','dns_sec',"varbinary(255) NOT NULL default ''");
 409          $this->_fixTable('central_conf','web_conf',"varbinary(255) NOT NULL default ''");
 410          $this->_fixTable('central_conf','web_path',"varbinary(255) NOT NULL default ''");
 411          $this->_fixTable('central_conf','db_server',"varbinary(255) NOT NULL default ''");
 412          $this->_fixTable('central_conf','db_name',"varbinary(255) NOT NULL default ''");
 413          $this->_fixTable('central_conf','db_user',"varbinary(255) NOT NULL default ''");
 414          $this->_fixTable('central_conf','db_pwd',"varbinary(255) NOT NULL default ''");
 415          $this->_fixTable('central_conf','AA_SITE_PATH',"varbinary(255) NOT NULL default ''");
 416          $this->_fixTable('central_conf','AA_BASE_DIR',"varbinary(255) NOT NULL default ''");
 417          $this->_fixTable('central_conf','AA_HTTP_DOMAIN',"varbinary(255) NOT NULL default ''");
 418          $this->_fixTable('central_conf','AA_ID',"varbinary(32) NOT NULL default ''");
 419          $this->_fixTable('central_conf','ORG_NAME',"varbinary(255) NOT NULL default ''");
 420          $this->_fixTable('central_conf','ERROR_REPORTING_EMAIL',"varbinary(255) NOT NULL default ''");
 421          $this->_fixTable('central_conf','ALERTS_EMAIL',"varbinary(255) NOT NULL default ''");
 422          $this->_fixTable('central_conf','IMG_UPLOAD_URL',"varbinary(255) NOT NULL default ''");
 423          $this->_fixTable('central_conf','IMG_UPLOAD_PATH',"varbinary(255) NOT NULL default ''");
 424          $this->_fixTable('central_conf','FILEMAN_BASE_DIR',"varbinary(255) NOT NULL default ''");
 425          $this->_fixTable('central_conf','FILEMAN_BASE_URL',"varbinary(255) NOT NULL default ''");
 426          $this->_fixTable('central_conf','AA_ADMIN_USER',"varbinary(30) NOT NULL default ''");
 427          $this->_fixTable('central_conf','AA_ADMIN_PWD',"varbinary(30) NOT NULL default ''");
 428          $this->_fixTable('content','item_id',"varbinary(16) NOT NULL default ''");
 429          $this->_fixTable('content','field_id',"varbinary(16) NOT NULL default ''");
 430          $this->_fixTable('discussion','id',"varbinary(16) NOT NULL default ''");
 431          $this->_fixTable('discussion','parent',"varbinary(16) NOT NULL default ''");
 432          $this->_fixTable('discussion','item_id',"varbinary(16) NOT NULL default ''");
 433          $this->_fixTable('ef_categories','category_id',"varbinary(16) NOT NULL default ''");
 434          $this->_fixTable('ef_categories','target_category_id',"varbinary(16) NOT NULL default ''");
 435          $this->_fixTable('ef_permissions','slice_id',"varbinary(16) NOT NULL default ''");
 436          $this->_fixTable('email','owner_module_id',"varbinary(16) NOT NULL default ''");
 437          $this->_fixTable('external_feeds','slice_id',"varbinary(16) NOT NULL default ''");
 438          $this->_fixTable('external_feeds','remote_slice_id',"varbinary(16) NOT NULL default ''");
 439          $this->_fixTable('event','id',"varbinary(32) NOT NULL default ''");
 440          $this->_fixTable('feedmap','from_slice_id',"varbinary(16) NOT NULL default ''");
 441          $this->_fixTable('feedmap','from_field_id',"varbinary(16) NOT NULL default ''");
 442          $this->_fixTable('feedmap','to_slice_id',"varbinary(16) NOT NULL default ''");
 443          $this->_fixTable('feedmap','to_field_id',"varbinary(16) NOT NULL default ''");
 444          $this->_fixTable('feedperms','from_id',"varbinary(16) NOT NULL default ''");
 445          $this->_fixTable('feedperms','to_id',"varbinary(16) NOT NULL default ''");
 446          $this->_fixTable('feeds','from_id',"varbinary(16) NOT NULL default ''");
 447          $this->_fixTable('feeds','to_id',"varbinary(16) NOT NULL default ''");
 448          $this->_fixTable('feeds','category_id',"varbinary(16) NOT NULL default ''");
 449          $this->_fixTable('feeds','to_category_id',"varbinary(16) NOT NULL default ''");
 450          $this->_fixTable('field','id',"varbinary(16) NOT NULL default ''");
 451          $this->_fixTable('field','slice_id',"varbinary(16) NOT NULL default ''");
 452          $this->_fixTable('field','content_id',"varbinary(16) default NULL");
 453          $this->_fixTable('jump','slice_id',"varbinary(16) NOT NULL default ''");
 454          $this->_fixTable('jump','dest_slice_id',"varbinary(16) NOT NULL default ''");
 455          $this->_fixTable('object_float','object_id',"varbinary(16) NOT NULL default ''");
 456          $this->_fixTable('object_float','property',"varbinary(32) NOT NULL default ''");
 457          $this->_fixTable('object_integer','object_id',"varbinary(16) NOT NULL default ''");
 458          $this->_fixTable('object_integer','property',"varbinary(32) NOT NULL default ''");
 459          $this->_fixTable('object_text','object_id',"varbinary(16) NOT NULL default ''");
 460          $this->_fixTable('object_text','property',"varbinary(32) NOT NULL default ''");
 461          $this->_fixTable('pagecache','id',"varbinary(32) NOT NULL default ''");
 462          $this->_fixTable('pagecache_str2find','pagecache_id',"varbinary(32) NOT NULL default ''");
 463          $this->_fixTable('polls','id',"varbinary(32) NOT NULL default ''");
 464          $this->_fixTable('polls','module_id',"varbinary(16) NOT NULL default ''");
 465          $this->_fixTable('polls','design_id',"varbinary(32) NOT NULL default ''");
 466          $this->_fixTable('polls','aftervote_design_id',"varbinary(32) NOT NULL default ''");
 467          $this->_fixTable('polls_answer','id',"varbinary(32) NOT NULL default ''");
 468          $this->_fixTable('polls_answer','poll_id',"varbinary(32) NOT NULL default ''");
 469          $this->_fixTable('polls_design','id',"varbinary(32) NOT NULL default ''");
 470          $this->_fixTable('polls_ip_lock','poll_id',"varbinary(32) NOT NULL default ''");
 471          $this->_fixTable('polls_log','answer_id',"varbinary(32) NOT NULL default ''");
 472          $this->_fixTable('polls_design','module_id',"varbinary(16) NOT NULL default ''");
 473          $this->_fixTable('polls_ip_lock','voters_ip',"varbinary(16) NOT NULL");
 474          $this->_fixTable('polls_log','voters_ip',"varbinary(16) NOT NULL default ''");
 475          $this->_fixTable('post2shtml','id',"varbinary(32) NOT NULL default ''");
 476          $this->_fixTable('profile','slice_id',"varbinary(16) NOT NULL default ''");
 477          $this->_fixTable('relation','source_id',"varbinary(16) NOT NULL default ''");
 478          $this->_fixTable('relation','destination_id',"varbinary(32) NOT NULL default ''");
 479          $this->_fixTable('rssfeeds','slice_id',"varbinary(16) NOT NULL default ''");
 480          $this->_fixTable('site','id',"varbinary(16) NOT NULL default ''");
 481          $this->_fixTable('site_spot','site_id',"varbinary(16) NOT NULL default ''");
 482          $this->_fixTable('slice','id',"varbinary(16) NOT NULL default ''");
 483          $this->_fixTable('slice','type',"varbinary(16) default NOT");
 484          $this->_fixTable('slice','mlxctrl',"varbinary(32) NOT NULL default ''");
 485          $this->_fixTable('view','slice_id',"varbinary(16) NOT NULL default ''");
 486          $this->_fixTable('view','order1',"varbinary(16) default NULL");
 487          $this->_fixTable('view','order2',"varbinary(16) default NULL");
 488          $this->_fixTable('view','group_by1',"varbinary(16) default NULL");
 489          $this->_fixTable('view','group_by2',"varbinary(16) default NULL");
 490          $this->_fixTable('view','cond1field',"varbinary(16) default NULL");
 491          $this->_fixTable('view','cond1op',"varbinary(10) default NULL");
 492          $this->_fixTable('view','cond2field',"varbinary(16) default NULL");
 493          $this->_fixTable('view','cond2op',"varbinary(10) default NULL");
 494          $this->_fixTable('view','cond3field',"varbinary(16) default NULL");
 495          $this->_fixTable('view','cond3op',"varbinary(10) default NULL");
 496          $this->_fixTable('view','field1',"varbinary(16) default NULL");
 497          $this->_fixTable('view','field2',"varbinary(16) default NULL");
 498          $this->_fixTable('view','field3',"varbinary(16) default NULL");
 499  
 500  
 501  /*
 502          $this->_fixTable('alerts_collection','module_id',"varbinary(16) NOT NULL default ''");
 503          $this->_fixTable('alerts_collection','slice_id',"varbinary(16) default NULL");
 504          $this->_fixTable('alerts_collection_filter','collectionid',"varbinary(6) NOT NULL default ''");
 505          $this->_fixTable('alerts_collection_howoften','collectionid',"varbinary(6) NOT NULL default ''");
 506          $this->_fixTable('constant','id','varbinary(16) NOT NULL default \'\'');
 507          $this->_fixTable('constant','group_id','varbinary(16) NOT NULL default \'\'');
 508          $this->_fixTable('constant','class','varbinary(16) default NULL');
 509          $this->_fixTable('constant_slice','slice_id',"varbinary(16) default NULL");
 510          $this->_fixTable('constant_slice','group_id',"varbinary(16) NOT NULL default ''");
 511          $this->_fixTable('email_notify','slice_id',"varbinary(16) NOT NULL default ''");
 512          $this->_fixTable('item','id',"varbinary(16) NOT NULL default ''");
 513          $this->_fixTable('item','slice_id',"varbinary(16) NOT NULL default ''");
 514          $this->_fixTable('links','id',"varbinary(16) NOT NULL default ''");
 515          $this->_fixTable('membership','memberid','varbinary(32) NOT NULL');
 516          $this->_fixTable('module','id',"varbinary(16) NOT NULL default ''");
 517          $this->_fixTable('module','owner',"varbinary(16) NOT NULL default ''");
 518          $this->_fixTable('module','app_id',"varbinary(16) default NULL");
 519          $this->_fixTable('offline','id',"varbinary(16) NOT NULL default ''");
 520          $this->_fixTable('offline','digest',"varbinary(32) NOT NULL default ''");
 521          $this->_fixTable('perms','objectid',"varbinary(32) NOT NULL default ''");
 522          $this->_fixTable('perms','userid',"varbinary(32) NOT NULL default '0'");
 523          $this->_fixTable('perms','perm',"varbinary(32) NOT NULL default ''");
 524          $this->_fixTable('slice_owner','id',"varbinary(16) NOT NULL default ''");
 525          $this->_fixTable('users','type',"varbinary(10) NOT NULL default ''");
 526          $this->_fixTable('users','password',"varbinary(30) NOT NULL default ''");
 527          $this->_fixTable('users','uid',"varbinary(40) NOT NULL default ''");
 528  */
 529          return true;
 530      }
 531  
 532      /** Helper _fixTable function */
 533      function _fixTable($table, $field, $definition) {
 534          $db  = getDb();
 535          $SQL = "ALTER TABLE `$table` CHANGE `$field` `$field` $definition";
 536          $this->message($SQL);
 537          $db->query($SQL);
 538          $SQL = "UPDATE `$table` SET $field=TRIM(TRAILING '\0' FROM $field)";
 539          $this->message($SQL);
 540          $db->query($SQL);
 541          freeDb($db);
 542      }
 543  }
 544  
 545  /** There was change in Reader management functionality in AA v2.8.1 */
 546  class AA_Optimize_Readers_Login2id extends AA_Optimize {
 547  
 548      /** Name function
 549      * @return a message
 550      */
 551      function name() {
 552          return _m("Convert Readers login to reader id");
 553      }
 554  
 555      /** Description function
 556      * @return a message
 557      */
 558      function description() {
 559          return _m("There was change in Reader management functionality in AA v2.8.1, so readers are not internaly identified by its login, but by reader ID (item ID of reader in Reader slice). This is much more powerfull - you can create relations just as in normal slice. It works well without any change. The only problem is, if you set any slice to be editable by users from Reader slice. In that case the fields edited_by........ and posted_by........ are filled by readers login instead of reader id. You can fix it by \"Repair\".");
 560      }
 561  
 562      /** Test function
 563      * @return bool
 564      */
 565      function test() {
 566          $this->clear_report();
 567          $ret = true;  // which means OK
 568  
 569          // get all readers in array: id => arrary( name => ...)
 570          $readers         = FindReaderUsers('');
 571          $posted_by_found = $this->_test_field($readers, 'posted_by');
 572          if (count($posted_by_found) > 0) {
 573              $this->message(_m('%1 login names from reader slice found as records in item.posted_by which is wrong (There should be reader ID from AA v2.8.1). "Repair" will correct it.', array(count($posted_by_found))));
 574              $ret = false;
 575          }
 576          $edited_by_found = $this->_test_field($readers, 'edited_by');
 577          if (count($edited_by_found) > 0) {
 578              $this->message(_m('%1 login names from reader slice found as records in item.edited_by which is wrong (There should be reader ID from AA v2.8.1). "Repair" will correct it.', array(count($edited_by_found))));
 579              $ret = false;
 580          }
 581          return $ret;
 582      }
 583  
 584      /** test if we can find an item which was edited by reader and is identified
 585       *  by login name (instead of item_id)
 586       *  @return array of such users
 587       */
 588      function _test_field(&$readers, $item_field) {
 589          // get posted_by, edit_by, ... array:  posted_by => 1
 590          $SQL     = "SELECT DISTINCT $item_field FROM item";
 591          $editors = GetTable2Array($SQL, $item_field, 'aa_mark');
 592          $ret     = array();
 593          foreach ( $readers as $r_id => $reader ) {
 594              if ($reader['name'] AND isset($editors[$reader['name']])) {
 595                  $ret[$r_id] = $reader['name'];
 596              }
 597          }
 598          return $ret;
 599      }
 600  
 601      /** Repair function
 602      * @return bool
 603      */
 604      function repair() {
 605          $this->clear_report();
 606  
 607          // get all readers in array: id => arrary( name => ...)
 608          $readers = FindReaderUsers('');
 609          $posted_by_found = $this->_test_field($readers, 'posted_by');
 610          $edited_by_found = $this->_test_field($readers, 'edited_by');
 611          $db = getDb();
 612          if (count($posted_by_found) > 0) {
 613              foreach ($posted_by_found as $r_id => $r_login ) {
 614                  $SQL = "UPDATE item SET posted_by = '$r_id' WHERE posted_by = '$r_login'";
 615                  $db->query($SQL);
 616                  $this->message(_m('Column item.posted_by updated for %1 (id: %2).', array($r_login, $r_id)));
 617              }
 618          }
 619          if (count($edited_by_found) > 0) {
 620              foreach ($edited_by_found as $r_id => $r_login ) {
 621                  $SQL = "UPDATE item SET edited_by = '$r_id' WHERE edited_by = '$r_login'";
 622                  $db->query($SQL);
 623                  $this->message(_m('Column item.edited_by updated for %1 (id: %2).', array($r_login, $r_id)));
 624              }
 625          }
 626          return true;
 627      }
 628  }
 629  
 630  /** There was change in Reader management functionality in AA v2.8.1 */
 631  class AA_Optimize_Database_Structure extends AA_Optimize {
 632  
 633      /** Name function
 634      * @return a message
 635      */
 636      function name() {
 637          return _m("Checks if all tables have right columns and indexes");
 638      }
 639  
 640      /** Description function
 641      * @return a message
 642      */
 643      function description() {
 644          return _m("We are time to time add new table or collumn to existing table in order we can support new features. This option will update the datastructure to the last one. No data will be lost.");
 645      }
 646  
 647      /** Name function
 648      * @return bool
 649      */
 650      function test() {
 651          $this->clear_report();
 652          $ret = true;  // which means OK
 653  
 654          $db = getDb();
 655          foreach ( $db->table_names() as $table ) {
 656              $table_name = $table['table_name'];
 657              $db->query("SHOW CREATE TABLE $table_name" );
 658              if (!$db->next_record()) {
 659                  continue;
 660              }
 661              $table_SQL = $db->f('Create Table');
 662  
 663          }
 664          freeDb($db);
 665          return $ret;
 666  
 667      }
 668  
 669      /** Repair function
 670      * @return bool
 671      */
 672      function repair() {
 673          $this->clear_report();
 674  
 675          // get all readers in array: id => arrary( name => ...)
 676          $readers         = FindReaderUsers('');
 677          $posted_by_found = $this->_test_field($readers, 'posted_by');
 678          $db              = getDb();
 679          if (count($posted_by_found) > 0) {
 680              foreach ($posted_by_found as $r_id => $r_login ) {
 681                  $SQL = "UPDATE item SET posted_by = '$r_id' WHERE posted_by = '$r_login'";
 682                  $db->query($SQL);
 683                  $this->message(_m('Column item.posted_by updated for %1 (id: %2).', array($r_login, $r_id)));
 684              }
 685          }
 686          if (count($edited_by_found) > 0) {
 687              foreach ($edited_by_found as $r_id => $r_login ) {
 688                  $SQL = "UPDATE item SET edited_by = '$r_id' WHERE edited_by = '$r_login'";
 689                  $db->query($SQL);
 690                  $this->message(_m('Column item.edited_by updated for %1 (id: %2).', array($r_login, $r_id)));
 691              }
 692          }
 693          return true;
 694      }
 695  }
 696  
 697  
 698  /** Whole pagecache will be invalidated and deleted */
 699  class AA_Optimize_Clear_Pagecache extends AA_Optimize {
 700  
 701      /** Name function
 702      * @return a message
 703      */
 704      function name() {
 705          return _m("Clear Pagecache");
 706      }
 707  
 708      /** Description function
 709      * @return a message
 710      */
 711      function description() {
 712          return _m("Whole pagecache will be invalidated and deleted");
 713      }
 714  
 715      /** implemented actions within this class */
 716      function actions()      { return array('repair'); }
 717  
 718      /** Test function
 719      * @return bool
 720      */
 721      function test() {
 722          $this->message(_m('There is nothing to test.'));
 723          return true;
 724      }
 725  
 726      /** Deletes the pagecache - the renaming and deleting is much, much quicker,
 727       *  than easy DELETE FROM ...
 728       * @return bool
 729       */
 730      function repair() {
 731          $db  = getDb();
 732          $db->query('CREATE TABLE IF NOT EXISTS pagecache_new LIKE pagecache');
 733          $this->message(_m('Table pagecache_new created'));
 734          $db->query('CREATE TABLE IF NOT EXISTS pagecache_str2find_new LIKE pagecache_str2find');
 735          $this->message(_m('Table pagecache_str2find_new created'));
 736          $db->query('RENAME TABLE pagecache_str2find TO pagecache_str2find_bak, pagecache TO pagecache_bak');
 737          $this->message(_m('Renamed tables pagecache_* to pagecache_*_bak'));
 738          $db->query('RENAME TABLE pagecache_str2find_new TO pagecache_str2find, pagecache_new TO pagecache');
 739          $this->message(_m('Renamed tables pagecache_*_new to pagecache_*'));
 740          $db->query('DROP TABLE pagecache_str2find_bak, pagecache_bak');
 741          $this->message(_m('Old pagecache_*_bak tables dropped'));
 742          freeDb($db);
 743          return true;
 744      }
 745  }
 746  
 747  /** Fix inconcistency in pagecache
 748   *  Delete not existant keys in pagecache_str2find table
 749   */
 750  class AA_Optimize_Fix_Pagecache extends AA_Optimize {
 751  
 752      /** Name function
 753      * @return a message
 754      */
 755      function name() {
 756          return _m("Fix inconcistency in pagecache");
 757      }
 758  
 759      /** Description function
 760      * @return a message
 761      */
 762      function description() {
 763          return _m("Delete not existant keys in pagecache_str2find table");
 764      }
 765  
 766      /** Test function
 767      * @return bool
 768      */
 769      function test() {
 770          $row_count   = GetTable2Array("SELECT count(*) as count FROM pagecache_str2find", "aa_first", 'count');
 771          // $wrong_count = GetTable2Array("SELECT count(*) as count FROM pagecache_str2find LEFT JOIN pagecache ON pagecache_str2find.pagecache_id = pagecache.id WHERE pagecache.stored IS NULL", "aa_first", 'count');
 772          $bad_rows    = GetTable2Array("SELECT * FROM pagecache_str2find LEFT JOIN pagecache ON pagecache_str2find.pagecache_id = pagecache.id WHERE pagecache.stored IS NULL", "");
 773          if (!is_array($bad_rows)) {
 774              $bad_rows = array();
 775          }
 776          foreach ($bad_rows as $row) {
 777              $this->message(_m('id: %1, pagecache_id: %2, str2find: %3', array($row['id'], $row['pagecache_id'], $row['str2find'])));
 778          }
 779          $this->message(_m('We found %1 inconsistent rows from %2 in pagecache_str2find', array(count($bad_rows), $row_count)));
 780          // $this->message(_m('We found %1 inconsistent rows from %2 in pagecache_str2find', array($wrong_count, $row_count)));
 781          return true;
 782      }
 783  
 784      /** Deletes the pagecache - the renaming and deleting is much, much quicker,
 785       *  than easy DELETE FROM ...
 786       * @return bool
 787       */
 788      function repair() {
 789          $db  = getDb();
 790          $db->query('DELETE pagecache_str2find FROM pagecache_str2find LEFT JOIN pagecache ON pagecache_str2find.pagecache_id = pagecache.id WHERE pagecache.stored IS NULL');
 791          $this->message(_m('Inconsistent rows in pagecache_str2find removed'));
 792          freeDb($db);
 793          return true;
 794      }
 795  }
 796  
 797  /** Whole pagecache will be invalidated and deleted */
 798  class AA_Optimize_Copy_Content extends AA_Optimize {
 799  
 800      /** Name function
 801      * @return a message
 802      */
 803      function name() {
 804          return _m("Copy Content Table");
 805      }
 806  
 807      /** Description function
 808      * @return a message
 809      */
 810      function description() {
 811          return _m("Copy data for all items newer than short_id=1941629 from content table to content2 table. Used for recovery content table on Ecn server. Not usefull for any other users, I think.");
 812      }
 813  
 814      /** implemented actions within this class */
 815      function actions()      { return array('repair'); }
 816  
 817      /** Test function
 818      * @return a message
 819      */
 820      function test() {
 821          $this->message(_m('There is nothing to test.'));
 822          return true;
 823      }
 824  
 825      /** Deletes the pagecache - the renaming and deleting is much, much quicker,
 826       *  than easy DELETE FROM ...
 827       * @return bool
 828       */
 829      function repair() {
 830          $db  = getDb();
 831  
 832          $SQL = "INSERT INTO content2 SELECT content.* FROM content
 833                  LEFT JOIN item on content.item_id=item.id
 834                  WHERE item.short_id>1941629";
 835  
 836          /** Situation was:
 837           *     Content table was corrupted, so we replace i from backup. The last item in backup was short_id=1941629;
 838           *     After one day we found, that we restore the table from backup by wrong way, so it is corrupted for UTF slices
 839           *     So we decided to import old backup of content table to content2 table, and copy theer new items from content table
 840           *
 841           *
 842           *  First of all we insert new content, which is missing in content2 table
 843           *  INSERT INTO content2 SELECT content.* FROM content LEFT JOIN item on content.item_id=item.id WHERE item.short_id>1941629;
 844           *
 845           *  Then we switch from backup conten2 to content
 846           *  RENAME TABLE content TO contentblb, content2 TO content;
 847           *
 848           *  And now we update all content of the item, which was updated after the first switch (one day before)
 849           *  DELETE FROM content USING content, item WHERE content.item_id=item.id AND item.last_edit>1165360279 AND item.last_edit<1165500000 AND item.last_edit<>item.post_date AND item.short_id<1941629;
 850           *  INSERT INTO content SELECT contentblb.* FROM contentblb LEFT JOIN item on contentblb.item_id=item.id WHERE item.last_edit>1165360279 AND item.last_edit<1165500000 AND item.last_edit<>item.post_date AND item.short_id<1941629;
 851           *
 852           *
 853           *  $db->query($SQL);
 854          */
 855          $this->message(_m('Coppied'));
 856  
 857          freeDb($db);
 858          return true;
 859      }
 860  }
 861  
 862  /** Creates upload directory for current slice (if not already created) **/
 863  class AA_Optimize_Create_Upload_Dir extends AA_Optimize {
 864  
 865      /** Name function
 866      * @return a message
 867      */
 868      function name() {
 869          return _m("Create upload directory for current slice");
 870      }
 871  
 872      /** Description function
 873      * @return a message
 874      */
 875      function description() {
 876          return _m("see IMG_UPLOAD_PATH parameter in config.php3 file");
 877      }
 878  
 879      /** implemented actions within this class */
 880      function actions()      { return array('repair'); }
 881  
 882      /** Test function
 883      * @return a message
 884      */
 885      function test() {
 886          $this->message(_m('There is nothing to test.'));
 887          return true;
 888      }
 889  
 890      /** Main update function
 891       *  @return bool
 892       */
 893      function repair() {
 894          if ($path = Files::destinationDir(AA_Slices::getSlice($GLOBALS['slice_id']))) {
 895              $this->message(_m('OK, %1 created', array($path)));
 896              return true;
 897          }
 898          $this->message(Files::lastErr());
 899          return false;
 900      }
 901  }
 902  
 903  
 904  /** Prints out the metabase row for include/metabase.class.php3 file
 905   *  (used by AA developers to update database definition tempate)"
 906   **/
 907  class AA_Optimize_Generate_Metabase_Row extends AA_Optimize {
 908  
 909      /** Name function
 910      * @return a message
 911      */
 912      function name() {
 913          return _m("Generate metabase PHP row");
 914      }
 915  
 916      /** Description function
 917      * @return a message
 918      */
 919      function description() {
 920          return _m("prints out the metabase row for include/metabase.class.php3 file (used by AA developers to update database definition tempate)");
 921      }
 922  
 923      /** implemented actions within this class */
 924      function actions()      { return array('repair'); }
 925  
 926      /** Main update function
 927       *  @return bool
 928       */
 929      function repair() {
 930          $metabase  = new AA_Metabase;
 931          $metabase->loadFromDb();
 932          echo '$instance = unserialize(\''. str_replace("'", '\\\'', serialize($metabase)) .'\');';
 933          exit;
 934      }
 935  }
 936  
 937  /** Set flag FLAG_TEXT_STORED for all content, where field is marked as text
 938   *  field, and reset it for numer fields
 939   **/
 940  class AA_Optimize_Fix_Content_Column extends AA_Optimize {
 941  
 942      /** Name function
 943      * @return a message
 944      */
 945      function name() {
 946          return _m("Set right content column for field");
 947      }
 948  
 949      /** Description function
 950      * @return a message
 951      */
 952      function description() {
 953          return _m("Set flag FLAG_TEXT_STORED for all content, where field is marked as text field, and reset it for numer fields");
 954      }
 955  
 956      /** implemented actions within this class */
 957      function actions()      { return array('test','repair'); }
 958  
 959      /** Test function
 960      * @return a message
 961      */
 962      function test() {
 963          $bad_rows = GetTable2Array("SELECT content.item_id, content.field_id FROM content INNER JOIN item ON content.item_id=item.id INNER JOIN slice ON item.slice_id=slice.id INNER JOIN field ON field.slice_id=slice.id WHERE content.field_id = field.id AND field.text_stored=1 AND (content.flag & 64) = 0",'');
 964          if (empty($bad_rows)) {
 965               $this->message(_m('No problem found, hurray'));
 966               return true;
 967          }
 968          foreach ($bad_rows as $index => $row) {
 969              $this->message(_m('id: %1, field_id: %2', array(unpack_id($row['item_id']), $row['field_id'])));
 970              if ($index > 240) {
 971                   $this->message(_m('and more...'));
 972                   break;
 973              }
 974          }
 975          $this->message(_m('We found %1 inconsistent rows in content table', array(count($bad_rows))));
 976          // $this->message(_m('We found %1 inconsistent rows from %2 in pagecache_str2find', array($wrong_count, $row_count)));
 977          return false;
 978      }
 979  
 980      /** Main update function
 981       *  @return bool
 982       */
 983      function repair() {
 984          $db  = getDb();
 985          $bad_rows = GetTable2Array("SELECT content.item_id, content.field_id FROM content INNER JOIN item ON content.item_id=item.id INNER JOIN slice ON item.slice_id=slice.id INNER JOIN field ON field.slice_id=slice.id WHERE content.field_id = field.id AND field.text_stored=1 AND (content.flag & 64) = 0",'');
 986          foreach ($bad_rows as $index => $row) {
 987              $SQL = "UPDATE content SET flag = flag | 64 WHERE item_id = '".quote($row['item_id'])."' AND field_id = '".quote($row['field_id'])."'";
 988              $db->query($SQL);
 989              $this->message(_m('fixed (id-field): %1 - %2 (%3)', array(unpack_id($row['item_id']), $row['field_id'], $SQL)));
 990              if ($index > 240) {
 991                   $this->message(_m('and more...'));
 992              }
 993          }
 994          $this->message(_m('We fixed %1 inconsistent rows in content table', array(count($bad_rows))));
 995          // $this->message(_m('We found %1 inconsistent rows from %2 in pagecache_str2find', array($wrong_count, $row_count)));
 996          freeDb($db);
 997          return true;
 998      }
 999  }
1000  
1001  
1002  /** Delete discussion comments for not existing items
1003   */
1004  class AA_Optimize_Item_Discussion extends AA_Optimize {
1005  
1006      /** Name function
1007      * @return a message
1008      */
1009      function name() {
1010          return _m("Delete discussion comments for not existing items");
1011      }
1012  
1013      /** Description function
1014      * @return a message
1015      */
1016      function description() {
1017          return _m("");
1018      }
1019  
1020      /** Test function
1021      * tests for duplicate entries
1022      * @return bool
1023      */
1024      function test() {
1025          $SQL      = 'SELECT count(*) as disc_count, item_id FROM `discussion` LEFT JOIN item ON discussion.item_id = item.id WHERE item.short_id IS NULL GROUP BY discussion.item_id';
1026          $problems = GetTable2Array($SQL, "unpack:item_id", 'disc_count');
1027          if ($problems == false) {
1028              $this->message( _m('No problems found') );
1029              return true;
1030          }
1031          foreach ($problems as $item_id => $disc_count) {
1032              $this->message(_m('Problem for item %1 - %2 comments found', array($item_id, $disc_count)));
1033          }
1034          return false;
1035      }
1036  
1037      /** Repair the problem
1038      * @return bool
1039      */
1040      function repair() {
1041          $db       = getDb();
1042          $SQL      = 'SELECT count(*) as disc_count, item_id FROM `discussion` LEFT JOIN item ON discussion.item_id = item.id WHERE item.short_id IS NULL GROUP BY discussion.item_id';
1043          $problems = GetTable2Array($SQL, "", 'item_id');
1044          if (count((array)$problems) < 1) {
1045              $this->message( _m('No problems found') );
1046              return true;
1047          }
1048          $SQL = 'DELETE FROM `discussion` WHERE '. Cvarset::sqlin('item_id', $problems);
1049          $db->query($SQL);
1050          $SQL = "DELETE FROM `discussion` WHERE item_id = ''";
1051          $db->query($SQL);
1052          $this->message(_m('%1 problems solved', array(count($problems))));
1053          freeDb($db);
1054          return true;
1055      }
1056  }
1057  
1058  /**
1059   */
1060  class AA_Optimize_Multivalue_Duplicates extends AA_Optimize {
1061  
1062      /** Name function
1063      * @return a message
1064      */
1065      function name() {
1066          return _m("Multivalue Duplicates");
1067      }
1068  
1069      /** Description function
1070      * @return a message
1071      */
1072      function description() {
1073          return _m("Removes duplicate values in multivalue text fields");
1074      }
1075  
1076      /** Test function
1077      * tests for duplicate entries
1078      * @return bool
1079      */
1080      function test() {
1081          $ret = true;
1082  
1083          // test wrong destination slices
1084          $SQL      = "SELECT `item_id`, `field_id`, `text`, count(*) AS `cnt` FROM `content` WHERE (flag && 64) GROUP BY `item_id`, `field_id`, `text` HAVING `cnt` >1";
1085          $err_text = GetTable2Array($SQL, '', 'aa_fields');
1086  
1087          if (is_array($err_text) AND count($err_text) > 0) {
1088              $this->message( _m('%1 duplicates found in text fields', array(count($err_text))));
1089              foreach ($err_text as $wrong) {
1090                  $this->message( _m('Duplicates (%4) in item %1 - field %2 - value %3', array(unpack_id($wrong['item_id']),$wrong['field_id'],$wrong['text'],$wrong['cnt'])));
1091              }
1092              $ret = false;
1093          }
1094  
1095          $SQL      = "SELECT `item_id`, `field_id`, `number`, count(*) AS `cnt` FROM `content` WHERE (flag && 64) = 0 GROUP BY `item_id`, `field_id`, `number` HAVING `cnt` >1";
1096          $err_num  = GetTable2Array($SQL, '', 'aa_fields');
1097  
1098          if (is_array($err_num) AND count($err_num) > 0) {
1099              $this->message( _m('%1 duplicates found in numeric fields', array(count($err_num))));
1100              foreach ($err_num as $wrong) {
1101                  $this->message( _m('Duplicates (%4) in item %1 - field %2 - value %3', array(unpack_id($wrong['item_id']),$wrong['field_id'],$wrong['text'],$wrong['cnt'])));
1102              }
1103              $ret = false;
1104          }
1105  
1106          if ($ret ) {
1107              $this->message(_m('No duplicates found, hurray!'));
1108          }
1109          return $ret;
1110      }
1111  
1112      /** Name function
1113      * @return bool
1114      */
1115      function repair() {
1116          $db  = getDb();
1117  
1118          // test wrong destination slices
1119          $SQL = "SELECT to_id FROM feeds LEFT JOIN slice ON feeds.to_id=slice.id WHERE slice.id IS NULL";
1120          $err = GetTable2Array($SQL, '', 'unpack:to_id');
1121  
1122          if (is_array($err) AND count($err)>0 ) {
1123              foreach ($err as $wrong_slice_id) {
1124                  $SQL = 'DELETE FROM `feeds` WHERE `to_id`=\''.q_pack_id($wrong_slice_id).'\'';
1125                  $db->query($SQL);
1126              }
1127          }
1128  
1129          // test wrong source slices
1130          $SQL = "SELECT from_id FROM feeds LEFT JOIN slice ON feeds.from_id=slice.id WHERE slice.id IS NULL";
1131          $err = GetTable2Array($SQL, '', 'unpack:from_id');
1132  
1133          if (is_array($err) AND count($err)>0 ) {
1134              foreach ($err as $wrong_slice_id) {
1135                  $SQL = 'DELETE FROM `feeds` WHERE `from_id`=\''.q_pack_id($wrong_slice_id).'\'';
1136                  $db->query($SQL);
1137              }
1138          }
1139  
1140          freeDb($db);
1141          return true;
1142      }
1143  }
1144  
1145  ?>

title

Description

title

Description

title

Description

title

title

Body