Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
system_integrity_invalid_links.php
1 <?php
29 error_reporting(E_ALL);
30 if (count($_SERVER['argv']) < 3 || php_sapi_name() != 'cli') {
31  echo "This script needs to be run in the following format:\n\n";
32  echo "\tphp system_integrity_invalid_links.php [SYSTEM_ROOT] [-delete|-check] [-remove_notice_links]\n\n";
33  exit(1);
34 }
35 
36 $SYSTEM_ROOT = (isset($_SERVER['argv'][1])) ? $_SERVER['argv'][1] : '';
37 if (empty($SYSTEM_ROOT)) {
38  echo "ERROR: You need to supply the path to the System Root as the first argument\n";
39  exit();
40 }
41 
42 if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT.'/core/include/init.inc')) {
43  echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
44  exit();
45 }
46 
47 require_once $SYSTEM_ROOT.'/core/include/init.inc';
48 
49 $ACTION = (isset($_SERVER['argv'][2])) ? $_SERVER['argv'][2] : '';
50 $ACTION = ltrim($ACTION, '-');
51 if (empty($ACTION) || ($ACTION != 'delete' && $ACTION != 'check')) {
52  echo "ERROR: No action specified";
53  exit();
54 }//end if
55 
56 $remove_notice_links = FALSE;
57 $NOTICE_ACTION = (isset($_SERVER['argv'][3])) ? $_SERVER['argv'][3] : '';
58 $NOTICE_ACTION = ltrim($NOTICE_ACTION, '-');
59 if ($NOTICE_ACTION == 'remove_notice_links') {
60  if ($ACTION != 'delete') trigger_error("Cannot remove notice links if the action is not '-delete'", E_USER_ERROR);
61  $remove_notice_links = TRUE;
62 } else if ($NOTICE_ACTION != '') {
63  if ($ACTION == 'delete') echo "\nThird argument was mentioned but was not '-remove_notice_links'. Notice Links will not be removed\n\n";
64 }
65 
66 // login as root user to avoid problems with safe edit assets
67 $root_user = &$GLOBALS['SQ_SYSTEM']->am->getSystemAsset('root_user');
68 if (!$GLOBALS['SQ_SYSTEM']->setCurrentUser($root_user)) {
69  echo "ERROR: Failed login in as root user";
70  exit();
71 }
72 
73 $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db');
74 $sql = "SELECT * FROM sq_ast_lnk a WHERE a.minorid NOT IN (SELECT assetid FROM sq_ast)";
75 if (!$remove_notice_links && $ACTION != 'check') $sql .= " AND a.link_type <> :link_type";
76 
77 $sql .= " UNION SELECT * FROM sq_ast_lnk b WHERE b.majorid NOT IN (SELECT assetid FROM sq_ast) AND b.majorid <> '0'";
78 if (!$remove_notice_links && $ACTION != 'check') $sql .= " AND b.link_type <> :link_type";
79 
80 try {
81  $query = MatrixDAL::preparePdoQuery($sql);
82  if (!$remove_notice_links && $ACTION != 'check') MatrixDAL::bindValueToPdo($query, 'link_type', SQ_LINK_NOTICE);
83  $links = DAL::executePdoAssoc($query);
84  $link_count = count($links);
85 } catch (Exception $e) {
86  trigger_error('Unable to find invalid links due to database error: '.$e->getMessage(), E_USER_ERROR);
87 }
88 
89 $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
90 
91 if ($link_count == 0) {
92  echo "\nNo invalid links found\n";
93  exit(0);
94 } else {
95  echo "\nFound $link_count invalid links\n";
96  if ($ACTION == 'delete'){
97  echo 'This script is about to be run SYSTEM WIDE in DELETE mode. Are you sure you want to continue (y/n): ';
98  $confirm = rtrim(fgets(STDIN, 4094));
99  if ($confirm != 'y') exit(0);
100  } else {
101  exit(0);
102  }
103 }
104 
105 $GLOBALS['SQ_SYSTEM']->setRunLevel(SQ_RUN_LEVEL_FORCED);
106 $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
107 
108 foreach($links as $link) {
109 
110  //the upcoming queries have been copied over from Asset_Manager::deleteAssetLinkByLink().
111  if (!($link['link_type'] & SQ_SC_LINK_SIGNIFICANT) && !$remove_notice_links) continue;
112 
113  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
114 
115  // update the parents to tell them that they are going to be one kid less
116  $sql = 'UPDATE
117  sq_ast_lnk_tree
118  SET
119  num_kids = num_kids - 1
120  WHERE
121  treeid IN
122  (
123  SELECT
124  CASE WHEN
125  LENGTH(SUBSTR(t.treeid, 1, LENGTH(t.treeid) - '.SQ_CONF_ASSET_TREE_SIZE.')) != 0
126  THEN
127  SUBSTR(t.treeid, 1, LENGTH(t.treeid) - '.SQ_CONF_ASSET_TREE_SIZE.')
128  ELSE
129  \'-\'
130  END
131  FROM
132  sq_ast_lnk_tree t
133  WHERE
134  t.linkid = :linkid
135  )';
136  $update_tree_parents_query = MatrixDAL::preparePdoQuery($sql);
137  try {
138  MatrixDAL::bindValueToPdo($update_tree_parents_query, 'linkid', $link['linkid']);
139  MatrixDAL::execPdoQuery($update_tree_parents_query);
140  } catch (Exception $e) {
141  trigger_error('Unable to update the link tree for linkid: '.$link['linkid'].' due to database error: '.$e->getMessage(), E_USER_ERROR);
142  }
143 
144  // we can delete all the links under these nodes because it will be a clean start
145  // when we insert into the gap's we create below
146  $sql = 'DELETE FROM
147  sq_ast_lnk_tree
148  WHERE
149  treeid in
150  (
151  SELECT
152  ct.treeid
153  FROM
154  sq_ast_lnk_tree pt, sq_ast_lnk_tree ct
155  WHERE
156  pt.linkid = :linkid
157  AND (ct.treeid LIKE pt.treeid || '.'\''.'%'.'\''.'
158  OR ct.treeid = pt.treeid)
159  )';
160  $delete_tree_query = MatrixDAL::preparePdoQuery($sql);
161  try {
162  MatrixDAL::bindValueToPdo($delete_tree_query, 'linkid', $link['linkid']);
163  MatrixDAL::execPdoQuery($delete_tree_query);
164  } catch (Exception $e) {
165  trigger_error('Unable to delete tree links for linkid: '.$link['linkid'].' due to database error: '.$e->getMessage(), E_USER_ERROR);
166  }
167 
168  // Update sort orders of other children of this parent
169  $sql = 'UPDATE
170  sq_ast_lnk
171  SET
172  sort_order = sort_order - 1
173  WHERE
174  majorid = :majorid
175  AND sort_order > :sort_order';
176  $update_sort_order_query = MatrixDAL::preparePdoQuery($sql);
177  try {
178  MatrixDAL::bindValueToPdo($update_sort_order_query, 'majorid', $link['majorid']);
179  MatrixDAL::bindValueToPdo($update_sort_order_query, 'sort_order', $link['sort_order']);
180  MatrixDAL::execPdoQuery($update_sort_order_query);
181  } catch (Exception $e) {
182  trigger_error('Unable to update sort orders for majorid: '.$link['majorid'].' due to database error: '.$e->getMessage(), E_USER_ERROR);
183  }
184 
185  // Delete from the link table
186  try {
187  $bind_vars = Array (
188  'linkid' => $link['linkid'],
189  'majorid' => $link['majorid'],
190  );
191  MatrixDAL::executeQuery('core', 'deleteLink', $bind_vars);
192  } catch (Exception $e) {
193  trigger_error('Unable to delete link with linkid: '.$link['linkid'].' due to database error: '.$e->getMessage(), E_USER_ERROR);
194  }
195 
196  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
197  echo "Deleted Link ID: ".$link['linkid']." with Major ID: ".$link['majorid']." and Minor ID: ".$link['minorid']."\n";
198 
199 } // end foreach link
200 
201 $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
202 
203 $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db');
204 
205 $sql = 'SELECT count(*)
206  FROM sq_ast a
207  WHERE a.assetid NOT IN (SELECT minorid from sq_ast_lnk)
208  AND a.assetid NOT IN (SELECT majorid from sq_ast_lnk)';
209 
210 try {
211  $query = MatrixDAL::preparePdoQuery($sql);
212  $orphans = DAL::executePdoOne($query);
213 } catch (Exception $e) {
214  trigger_error('Unable to count orphaned assets due to database error: '.$e->getMessage(), E_USER_ERROR);
215 }
216 
217 if (!empty($orphans)) echo "There are $orphans orphan assets found. You must run system_integrity_orphaned_assets.php on the root folder to rescue these assets.\n";
218 
219 $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
220 $GLOBALS['SQ_SYSTEM']->restoreRunLevel();