Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
import.inc
1 <?php
17 require_once SQ_FUDGE_PATH.'/general/file_system.inc';
18 
37 function get_import_actions($import_file)
38 {
39  // parse the import XML file
40  if (!is_file($import_file)) {
41  trigger_error('Import file "'.$import_file.'" does not exist', E_USER_ERROR);
42  }
43 
44  // bug fix #5410 "Import Assets from XML Tool" running out of memory
45  // if we are on command line then dont worry about memory exhaustion
46  // issue do the whole XML file altogether if the request is coming from
47  // the web interface as mentioned on the bug report then execute the
48  // code block in else statment
49  if ((php_sapi_name() == 'cli')) {
50  $index = Array();
51  $xml_import_vals = Array();
52  $import_actions = Array();
53  $p = xml_parser_create();
54 
55  xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
56  xml_parser_set_option($p, XML_OPTION_SKIP_WHITE, 1);
57 
58  $xml_file = file_to_string($import_file);
59  xml_parse_into_struct($p, $xml_file, $xml_import_vals, $index);
60 
61  // print an error if one occured
62  if ($error_code = xml_get_error_code($p)) {
63  echo 'XML Error: '.xml_error_string($error_code).' Line:'.xml_get_current_line_number($p).' Col:'.xml_get_current_column_number($p)."\n";
64  exit();
65  }
66 
67  reset($xml_import_vals);
68  populate_import_action_array($import_actions, $xml_import_vals);
69 
70  } else {
71  // get few actions at a time from the XML so that while perforing
72  // populate_import_action_array() on it we dont run out of memory
73  $actions = Array();
74  $import_actions = Array();
75  $fh = fopen($import_file, 'r');
76  $old_exec_time = ini_get('max_execution_time');
77  // set higher execution time to allow matrix
78  // to read from the xml that might be quiet big
79  set_time_limit (200);
80  $xml_header = '';
81  while(!feof($fh)) {
82  $p = xml_parser_create();
83  xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
84  xml_parser_set_option($p, XML_OPTION_SKIP_WHITE, 1);
85 
86  $xml_import_vals = Array();
87  $chunk_import_action = Array();
88  $index = Array();
89  $content = '<actions>';
90  $count = 0;
91 
92  // make Matrix read atleast 500 lines and the last line read must
93  // always be end tag </action> so that the xml constructed is valid
94  do {
95  if (!($line = fgets($fh, 9999))) break;
96 
97  // skip the xml declaration and the starting tag for <actions>
98  // but if we are on the </actions> that means we are done with file
99  // break out or else there will be a infinite looping in this do...while
100  if (trim($line) == '') continue;
101  if (preg_match('/(<actions>)$/', trim($line))) continue;
102  if (preg_match('/(^<\?xml version)/', trim($line))) {
103  $xml_header = $line;
104  continue;
105  }
106  if (preg_match('/(<\/actions>)$/', trim($line))) break;
107 
108  $content = $content.$line;
109  $count++;
110  } while (!preg_match('/(<\/action>)$/', $content) || $count < 500);
111  $content .= '</actions>';
112 
113  if ($content != '<actions></actions>') {
114  if ($xml_header != '') $content = $xml_header.$content;
115  xml_parse_into_struct($p, $content, $xml_import_vals, $index);
116 
117  // print an error if one occured
118  if ($error_code = xml_get_error_code($p)) {
119  echo 'XML Error: '.xml_error_string($error_code).' Line:'.xml_get_current_line_number($p).' Col:'.xml_get_current_column_number($p)."\n";
120  exit();
121  }
122  }
123  xml_parser_free($p);
124 
125  reset($xml_import_vals);
126  populate_import_action_array($chunk_import_action, $xml_import_vals);
127  if (!empty($chunk_import_action)) $actions = array_merge($actions, $chunk_import_action['actions'][0]['action']);
128  }
129 
130  // restore the original max execution time
131  set_time_limit($old_exec_time);
132  $import_actions['actions'][0]['action'] = $actions;
133  }
134 
135  return $import_actions;
136 
137 }//end get_import_actions()
138 
139 
149 function populate_import_action_array(&$store, &$vals)
150 {
151  for (current($vals); NULL !== ($k = key($vals)); next($vals)) {
152  $data = $vals[$k];
153  $value = array_get_index($data, 'value', '');
154  $tag = array_get_index($data, 'tag', '');
155 
156  switch ($data['type']) {
157  case 'complete' : // FOUND A LEAF NODE
158 
159  if (isset($store[$tag])) {
160  $max = count($store[$tag]);
161  if (isset($data['attributes']) && count($data['attributes'])) {
162  foreach ($data['attributes'] as $n => $v) {
163  $store[$tag][$max][$n] = $v;
164  }
165  }
166  $store[$tag][$max]['_value'] = $value;
167  } else {
168  if (isset($data['attributes']) && count($data['attributes'])) {
169  foreach ($data['attributes'] as $n => $v) {
170  $store[$tag][0][$n] = $v;
171  }
172  $store[$tag][0]['_value'] = $value;
173  } else {
174  $store[$tag][0] = $value;
175  }
176  }
177 
178  break;
179 
180  case 'open' : // OPENING A NEW TAG
181 
182  // call next here or it will never be called
183  next($vals);
184 
185  if (!isset($store[$tag]) || !sizeof($store[$tag])) {
186  $store[$tag] = Array();
187  }
188 
189  $max = count($store[$tag]);
190  if (isset($data['attributes']) && count($data['attributes'])) {
191  foreach ($data['attributes'] as $n => $v) {
192  $store[$tag][$max][$n] = $v;
193  }
194  }
195  populate_import_action_array($store[$tag][$max], $vals);
196 
197  break;
198 
199  case 'close' : // CLOSING THE OPENED TAG
200 
201  // we return from the function here so
202  // we will end up one level up (ie. just after
203  // the populate_import_action_array fn call in the open case).
204  return;
205 
206  break;
207  }//end switch
208 
209  }//end for
210 
211 }//end populate_import_action_array()
212 
213 
226 function execute_import_action($action, &$outputs, $input_values=array())
227 {
228  $settings = Array();
229  $state = Array();
230 
231  $action_class = 'trigger_action_'.$action['action_type'][0];
232  $GLOBALS['SQ_SYSTEM']->am->includeAsset($action_class);
233 
234  // we call execute as a static method, but instantiate for method_exists
235  $class_instance = new $action_class;
236 
237  // gather settings required for the action
238  foreach ($action as $key => $value) {
239  // skip action metadata
240  if ($key == 'action_id') continue;
241  if ($key == 'action_type') continue;
242 
243  $value = get_import_action_input_value($action, $key, $outputs, $input_values);
244 
245  if (strtolower(SQ_CONF_DEFAULT_CHARACTER_SET) != 'utf-8') {
246  $pattern = '/((&#[0-9]*;))/';
247  preg_match_all($pattern, $value, $matches);
248 
249  $matches = $matches[0];
250  $replacement = Array();
251 
252  foreach ($matches as $match) {
253  $str = str_replace('&#', '', $match);
254  $str= intval(str_replace(';', '', $str));
255  if ($str > 126 && $str < 256) {
256  $new_value = chr($str);
257  } else {
258  $new_value = $match;
259  }
260  $replacement[] = $new_value;
261  }
262  $value = str_replace($matches, $replacement, $value);
263  $value = preg_replace('|<br/>|', chr(13), $value);
264  }
265 
266  if ($key == 'asset') {
267  // this is a special case where the value populates
268  // the state array for the trigger action so it knows what
269  // asset to perform the action on (if any)
270  $state['assetid'] = $value;
271  continue;
272  }
273 
274  $function_name = 'addSetting'.ucfirst($key);
275 
276  if (method_exists($class_instance, $function_name)) {
277  eval('$settings = '.$action_class.'::'.$function_name.'($value, $settings);');
278  continue;
279  }
280 
281  $settings[$key] = $value;
282 
283  }
284 
285  eval('$output = '.$action_class.'::execute($settings, $state);');
286  if ($output === FALSE) return FALSE;
287 
288  $outputs[$action['action_id'][0]] = $output;
289 
290  if ($action_class == 'trigger_action_set_attribute_value' && isset($output['attribute']) && $output['attribute'] == 'varieties'){
291  if (isset($output['assetid'])) {
292  $image = $GLOBALS['SQ_SYSTEM']->am->getAsset($output['assetid']);
293  if ($image && $image->type() == 'image'){
294  $edit_fns = $image->getEditFns();
295  $edit_fns->_recreateVarietyImages($image);
296  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($image);
297  }
298  }
299  }
300 
301  if ($action_class == 'trigger_action_create_asset' && isset($output['assetid'])) {
302  // lets see if the asset we just imported is a design_customisation..
303  $asset_imported = $GLOBALS['SQ_SYSTEM']->am->getAsset($output['assetid']);
304 
305  // .. and if it was update the design areas under it
306  if ($asset_imported && $asset_imported->type() == 'design_customisation') {
307  $parent_design = $asset_imported->getParentDesign();
308  $asset_imported->updateFromParent($parent_design);
309  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($parent_design);
310 
311  } else if ($asset_imported && strpos($asset_imported->type(), 'design_area') !== FALSE) {
312  // okie we just imported a design_area, we know its parent is design_customisation because
313  // a regular design's design_areas are created out of our parse file
314  // in this case we need to find the design_customisation first
315  // and then update it w.r.t its parent Design
316  $design_customisation = $GLOBALS['SQ_SYSTEM']->am->getAsset($settings['parentid'], 'design_customisation', TRUE);
317  if ($design_customisation) {
318  $parent_design = $design_customisation->getParentDesign();
319 
320  $custom_da_links = $design_customisation->getDesignAreaLink();
321  $data = Array();
322 
323  // get all the design_area on our customisations, and remove the ones that are
324  // already 'customised' by out customisation
325  foreach ($custom_da_links as $custom_da_link) {
326  $parent_da = $parent_design->getDesignAreaLink($custom_da_link['value']);
327  if (empty($parent_da)) continue;
328 
329  $data[$custom_da_link['value']] = Array($custom_da_link['minorid'], $custom_da_link['minor_type_code']);
330  }
331  $design_customisation_edit_fns = $design_customisation->getEditFns();
332 
333  if ($data && !$design_customisation_edit_fns->_updateDesignAreaLink($design_customisation, $data)) {
334  $design_customisation->updateFromParent($parent_design);
335  }
336 
337  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($design_customisation);
338  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($parent_design);
339  }
340 
341  }// end if/else
342 
343  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset_imported);
344 
345  }//end if (trigger_action_create_asset)
346 
347  return TRUE;
348 
349 }//end execute_import_action()
350 
351 
366 function get_import_action_input_value($action, $attribute, $outputs=Array(), $input_values=array())
367 {
368  // first make sure the attribute exists for this action
369  if (!isset($action[$attribute])) {
370  trigger_error('Failed getting '.$attribute.' for '.$action['action_type'][0].' action "'.$action['action_id'][0].'" - attribute is not defined for action', E_USER_ERROR);
371  } else {
372  $value = $action[$attribute][0];
373  }
374 
375  if (isset($input_values[(string)$value]) === true) return $input_values[$value];
376 
377  // loop until there are no more changes
378  do {
379  $current_value = $value;
380 
381  // if the value is an array, just return it
382  if (is_array($value)) return $value;
383  $matches = Array();
384  preg_match_all('|\[\[output://([^\]]+)\]\]|', $value, $matches);
385  foreach ($matches[0] as $key => $match) {
386  list($action_id, $output) = explode('.', $matches[1][$key], 2);
387  if (!isset($outputs[$action_id])) {
388  trigger_error('Failed getting '.$attribute.' for '.$action['action_type'][0].' action "'.$action['action_id'][0].'" - attribute references action "'.$action_id.'" that has not yet been run', E_USER_ERROR);
389  }
390  if (!isset($outputs[$action_id][$output])) {
391  trigger_error('Failed getting '.$attribute.' for '.$action['action_type'][0].' action "'.$action['action_id'][0].'" - attribute references action output "'.$output.'" that was not generated by action "'.$action_id.'"', E_USER_ERROR);
392  }
393  $value = str_replace($match, $outputs[$action_id][$output], $value);
394  }
395 
396  $matches = Array();
397  preg_match_all('|\[\[system://([^\]]+)\]\]|', $value, $matches);
398  foreach ($matches[0] as $key => $match) {
399  $system_asset = substr($match, 11, -2);
400  $assetid = $GLOBALS['SQ_SYSTEM']->am->getSystemAssetid($system_asset);
401  if (!$assetid) {
402  trigger_error('Failed getting system asset "'.$system_asset.'"', E_USER_ERROR);
403  }
404  $value = str_replace($match, $assetid, $value);
405  }
406 
407  $matches = Array();
408  preg_match_all('|\[\[conf://([^\]]+)\]\]|', $value, $matches);
409  $orig = (isset($matches[0][0]) ? $matches[0][0] : '');
410  foreach ($matches[1] as $key => $match) {
411  eval('$conf_value = SQ_CONF_'.strtoupper($match).';');
412  if ($match == 'system_root_urls') {
413  $tmp = explode("\n", $conf_value);
414  $conf_value = $tmp[0];
415  }
416  $value = str_replace($orig, $conf_value, $value);
417  }
418 
419  $matches = Array();
420  preg_match_all('|\[\[dal://([^\]_]+)_([^\]]+)\]\]|', $value, $matches);
421  if (!empty($matches[1]) && !empty($matches[2])) {
422  include SQ_DATA_PATH.'/private/conf/db.inc';
423  if (isset($db_conf[$matches[1][0]])) {
424  // DB name is correct
425  $dsn = $db_conf[$matches[1][0]];
426  // 'db' connection can be configured with multiple DSNs. But we only get the first DSN in the list for now.
427  if (($matches[1][0] == 'db') && !isset($dsn['DSN']) && isset($dsn[0])) {
428  $dsn = $dsn[0];
429  }
430  if (isset($dsn[$matches[2][0]])) {
431  // DSN section name is correct
432  $value = $dsn[$matches[2][0]];
433  }
434  }
435  }
436 
437  // construct-specific calls - will not work on a regular import
438  $matches = Array();
439  preg_match_all('|\[\[construct://([^\]]+)\]\]|', $value, $matches);
440  for ($ii = 0; $ii < count($matches[0]); $ii++) {
441  $construct_value = '';
442  switch ($matches[1][$ii]) {
443  case 'unit_test_path':
444  $construct_value = (defined('TC_CONF_UNIT_TEST_PATH') ? TC_CONF_UNIT_TEST_PATH : '');
445  break;
446  case 'construct_path':
447  $construct_value = (defined('TC_CONF_CONSTRUCT_PATH') ? TC_CONF_CONSTRUCT_PATH : '');
448  break;
449  case 'simpletest_path':
450  $construct_value = (defined('TC_CONF_SIMPLETEST_PATH') ? TC_CONF_SIMPLETEST_PATH : '');
451  break;
452  case 'matrix_url':
453  $construct_value = (defined('TC_CONF_MATRIX_URL') ? strip_url(TC_CONF_MATRIX_URL, TRUE): '');
454  break;
455  case 'time':
456  $construct_value = time();
457  break;
458  }
459  $value = str_replace($matches[0][$ii], $construct_value, $value);
460  }
461 
462  } while ($current_value != $value);
463 
464  return $value;
465 
466 }//end get_import_action_input_value()
467 
468 
479 function print_import_action_output_as_xml($action_id, $outputs, $indent='')
480 {
481  echo "$indent<output>\n";
482  echo "$indent\t<action_id>$action_id</action_id>\n";
483  foreach ($outputs as $key => $value) {
484  echo "$indent\t<$key>$value</$key>\n";
485  }
486  echo "$indent</output>\n";
487 
488 }//end print_import_action_output_as_xml()
489 
490 
491 ?>