00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00038 class SC_mod_tools_em_xmlhandler {
00045 var $emObj;
00046 var $extXMLResult = array();
00047 var $extensionsXML = array();
00048 var $reviewStates = null;
00049 var $useUnchecked = false;
00050 var $useObsolete = false;
00051
00064 function searchExtensionsXML($search, $owner='', $order='', $allExt=false, $allVer=false, $offset=0, $limit=500) {
00065 $where = '1=1';
00066 if ($search) {
00067 $where.= ' AND extkey LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($GLOBALS['TYPO3_DB']->escapeStrForLike($search, 'cache_extensions'), 'cache_extensions').'%\'';
00068 }
00069 if ($owner) {
00070 $where.= ' AND ownerusername='.$GLOBALS['TYPO3_DB']->fullQuoteStr($owner, 'cache_extensions');
00071 }
00072 if (strlen($owner) || $this->useUnchecked || $allExt) {
00073
00074 $where.= ' AND reviewstate >= 0';
00075 } else {
00076
00077 $where.= ' AND reviewstate > 0';
00078 }
00079 if (!$this->useObsolete && !$allExt) {
00080 $where.= ' AND state!=5';
00081 }
00082 switch ($order) {
00083 case 'author_company':
00084 $forder = 'authorname, authorcompany';
00085 break;
00086 case 'state':
00087 $forder = 'state';
00088 break;
00089 case 'cat':
00090 default:
00091 $forder = 'category';
00092 break;
00093 }
00094 $order = $forder.', title';
00095 if (!$allVer) {
00096 if ($this->useUnchecked) {
00097 $where .= ' AND lastversion>0';
00098 } else {
00099 $where .= ' AND lastreviewedversion>0';
00100 }
00101 }
00102 $this->catArr = array();
00103 $idx = 0;
00104 foreach ($this->emObj->defaultCategories['cat'] as $catKey => $tmp) {
00105 $this->catArr[$idx] = $catKey;
00106 $idx++;
00107 }
00108 $this->stateArr = array();
00109 $idx = 0;
00110 foreach ($this->emObj->states as $state => $tmp) {
00111 $this->stateArr[$idx] = $state;
00112 $idx++;
00113 }
00114
00115
00116 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*) as cnt', 'cache_extensions', $where);
00117 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
00118 $this->matchingCount = $row['cnt'];
00119 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00120
00121 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'cache_extensions', $where, '', $order, $offset.','.$limit);
00122 $this->extensionsXML = array();
00123 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
00124 $row['category'] = $this->catArr[$row['category']];
00125 $row['state'] = $this->stateArr[$row['state']];
00126
00127 if (!is_array($this->extensionsXML[$row['extkey']])) {
00128 $this->extensionsXML[$row['extkey']] = array();
00129 $this->extensionsXML[$row['extkey']]['downloadcounter'] = $row['alldownloadcounter'];
00130 }
00131 if (!is_array($this->extensionsXML[$row['extkey']]['versions'])) {
00132 $this->extensionsXML[$row['extkey']]['versions'] = array();
00133 }
00134 $row['dependencies'] = unserialize($row['dependencies']);
00135 $this->extensionsXML[$row['extkey']]['versions'][$row['version']] = $row;
00136 }
00137 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00138 }
00139
00140 function countExtensions() {
00141 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('extkey', 'cache_extensions', '1=1', 'extkey');
00142 $cnt = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
00143 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00144 return $cnt;
00145 }
00146
00152 function loadExtensionsXML() {
00153 $this->searchExtensionsXML('', '', '', true);
00154 }
00155
00161 function freeExtensionsXML() {
00162 unset($this->extensionsXML);
00163 $this->extensionsXML = array();
00164 }
00165
00172 function removeObsolete(&$extensions) {
00173 if($this->useObsolete) return;
00174
00175 reset($extensions);
00176 while (list($version, $data) = each($extensions)) {
00177 if($data['state']=='obsolete')
00178 unset($extensions[$version]);
00179 }
00180 }
00181
00189 function getReviewState($extKey, $version) {
00190 $where = 'extkey='.$GLOBALS['TYPO3_DB']->fullQuoteStr($extKey, 'cache_extensions').' AND version='.$GLOBALS['TYPO3_DB']->fullQuoteStr($version, 'cache_extensions');
00191 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('reviewstate', 'cache_extensions', $where);
00192 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
00193 return $row['reviewstate'];
00194 }
00195 $GLOBALS['TYPO3_DB']->sql_free_result($res);
00196 return 0;
00197 }
00198
00205 function checkReviewState(&$extensions) {
00206 if ($this->useUnchecked) return;
00207
00208 reset($extensions);
00209 while (list($version, $data) = each($extensions)) {
00210 if($data['reviewstate']<1)
00211 unset($extensions[$version]);
00212 }
00213 }
00214
00220 function checkReviewStateGlobal() {
00221 if($this->useUnchecked) return;
00222
00223 reset($this->extensionsXML);
00224 while (list($extkey, $data) = each($this->extensionsXML)) {
00225 while (list($version, $vdata) = each($data['versions'])) {
00226 if($vdata['reviewstate']<1) unset($this->extensionsXML[$extkey]['versions'][$version]);
00227 }
00228 if(!count($this->extensionsXML[$extkey]['versions'])) unset($this->extensionsXML[$extkey]);
00229 }
00230 }
00231
00232
00244 function startElement($parser, $name, $attrs) {
00245 switch($name) {
00246 case 'extensions':
00247 break;
00248 case 'extension':
00249 $this->currentExt = $attrs['extensionkey'];
00250 break;
00251 case 'version':
00252 $this->currentVersion = $attrs['version'];
00253 $this->extXMLResult[$this->currentExt]['versions'][$this->currentVersion] = array();
00254 break;
00255 default:
00256 $this->currentTag = $name;
00257 }
00258 }
00259
00267 function endElement($parser, $name) {
00268 switch($name) {
00269 case 'extension':
00270 unset($this->currentExt);
00271 break;
00272 case 'version':
00273 unset($this->currentVersion);
00274 break;
00275 default:
00276 unset($this->currentTag);
00277 }
00278 }
00279
00287 function characterData($parser, $data) {
00288 if(isset($this->currentTag)) {
00289 if(!isset($this->currentVersion) && $this->currentTag == 'downloadcounter') {
00290 $this->extXMLResult[$this->currentExt]['downloadcounter'] = trim($data);
00291 } elseif($this->currentTag == 'dependencies') {
00292 $data = @unserialize($data);
00293 if(is_array($data)) {
00294 $dep = array();
00295 foreach($data as $v) {
00296 $dep[$v['kind']][$v['extensionKey']] = $v['versionRange'];
00297 }
00298 $this->extXMLResult[$this->currentExt]['versions'][$this->currentVersion]['dependencies'] = $dep;
00299 }
00300 } elseif($this->currentTag == 'reviewstate') {
00301 $this->reviewStates[$this->currentExt][$this->currentVersion] = (int)trim($data);
00302 $this->extXMLResult[$this->currentExt]['versions'][$this->currentVersion]['reviewstate'] = (int)trim($data);
00303 } else {
00304 $this->extXMLResult[$this->currentExt]['versions'][$this->currentVersion][$this->currentTag] .= trim($data);
00305 }
00306 }
00307 }
00308
00315 function parseExtensionsXML($filename) {
00316
00317 $parser = xml_parser_create();
00318 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
00319 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
00320 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'utf-8');
00321 xml_set_element_handler($parser, array(&$this,'startElement'), array(&$this,'endElement'));
00322 xml_set_character_data_handler($parser, array(&$this,'characterData'));
00323
00324 $fp = gzopen($filename, 'rb');
00325 if (!$fp) {
00326 $content.= 'Error opening XML extension file "'.$filename.'"';
00327 return $content;
00328 }
00329 $string = gzread($fp, 0xffff);
00330
00331 $this->revCatArr = array();
00332 $idx = 0;
00333 foreach ($this->emObj->defaultCategories['cat'] as $catKey => $tmp) {
00334 $this->revCatArr[$catKey] = $idx++;
00335 }
00336
00337 $this->revStateArr = array();
00338 $idx = 0;
00339 foreach ($this->emObj->states as $state => $tmp) {
00340 $this->revStateArr[$state] = $idx++;
00341 }
00342
00343 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', '1=1');
00344
00345 $extcount = 0;
00346 @ini_set('pcre.backtrack_limit', 500000);
00347 do {
00348 if (preg_match('/.*(<extension\s+extensionkey="[^"]+">.*<\/extension>)/suU', $string, $match)) {
00349 // Parse content:
00350 if (!xml_parse($parser, $match[0], 0)) {
00351 $content.= 'Error in XML parser while decoding extensions XML file. Line '.xml_get_current_line_number($parser).': '.xml_error_string(xml_get_error_code($parser));
00352 $error = true;
00353 break;
00354 }
00355 $this->storeXMLResult();
00356 $this->extXMLResult = array();
00357 $extcount++;
00358 $string = substr($string, strlen($match[0]));
00359 } elseif(function_exists('preg_last_error') && preg_last_error()) {
00360 $errorcodes = array(
00361 0 => 'PREG_NO_ERROR',
00362 1 => 'PREG_INTERNAL_ERROR',
00363 2 => 'PREG_BACKTRACK_LIMIT_ERROR',
00364 3 => 'PREG_RECURSION_LIMIT_ERROR',
00365 4 => 'PREG_BAD_UTF8_ERROR'
00366 );
00367 $content.= 'Error in regular expression matching, code: '.$errorcodes[preg_last_error()].'<br />See <a href="http:
00368 $error = true;
00369 break;
00370 } else {
00371 if(gzeof($fp)) break;
00372 $string .= gzread($fp, 0xffff);
00373 }
00374 } while (true);
00375
00376 xml_parser_free($parser);
00377 gzclose($fp);
00378
00379 if(!$error) {
00380 $content.= '<p>The extensions list has been updated and now contains '.$extcount.' extension entries.</p>';
00381 }
00382
00383 return $content;
00384 }
00385
00386 function storeXMLResult() {
00387 foreach ($this->extXMLResult as $extkey => $extArr) {
00388 $max = -1;
00389 $maxrev = -1;
00390 $last = '';
00391 $lastrev = '';
00392 $usecat = '';
00393 $usetitle = '';
00394 $usestate = '';
00395 $useauthorcompany = '';
00396 $useauthorname = '';
00397 $verArr = array();
00398 foreach ($extArr['versions'] as $version => $vArr) {
00399 $iv = $this->emObj->makeVersion($version, 'int');
00400 if ($vArr['title']&&!$usetitle) {
00401 $usetitle = $vArr['title'];
00402 }
00403 if ($vArr['state']&&!$usestate) {
00404 $usestate = $vArr['state'];
00405 }
00406 if ($vArr['authorcompany']&&!$useauthorcompany) {
00407 $useauthorcompany = $vArr['authorcompany'];
00408 }
00409 if ($vArr['authorname']&&!$useauthorname) {
00410 $useauthorname = $vArr['authorname'];
00411 }
00412 $verArr[$version] = $iv;
00413 if ($iv>$max) {
00414 $max = $iv;
00415 $last = $version;
00416 if ($vArr['title']) {
00417 $usetitle = $vArr['title'];
00418 }
00419 if ($vArr['state']) {
00420 $usestate = $vArr['state'];
00421 }
00422 if ($vArr['authorcompany']) {
00423 $useauthorcompany = $vArr['authorcompany'];
00424 }
00425 if ($vArr['authorname']) {
00426 $useauthorname = $vArr['authorname'];
00427 }
00428 $usecat = $vArr['category'];
00429 }
00430 if ($vArr['reviewstate'] && ($iv>$maxrev)) {
00431 $maxrev = $iv;
00432 $lastrev = $version;
00433 }
00434 }
00435 if (!strlen($usecat)) {
00436 $usecat = 4;
00437 } else {
00438 if (isset($this->revCatArr[$usecat])) {
00439 $usecat = $this->revCatArr[$usecat];
00440 } else {
00441 $usecat = 4;
00442 }
00443 }
00444 if (isset($this->revStateArr[$usestate])) {
00445 $usestate = $this->revCatArr[$usestate];
00446 } else {
00447 $usestate = 999;
00448 }
00449 foreach ($extArr['versions'] as $version => $vArr) {
00450 $vArr['version'] = $version;
00451 $vArr['intversion'] = $verArr[$version];
00452 $vArr['extkey'] = $extkey;
00453 $vArr['alldownloadcounter'] = $extArr['downloadcounter'];
00454 $vArr['dependencies'] = serialize($vArr['dependencies']);
00455 $vArr['category'] = $usecat;
00456 $vArr['title'] = $usetitle;
00457 if ($version==$last) {
00458 $vArr['lastversion'] = 1;
00459 }
00460 if ($version==$lastrev) {
00461 $vArr['lastreviewedversion'] = 1;
00462 }
00463 $vArr['state'] = isset($this->revStateArr[$vArr['state']])?$this->revStateArr[$vArr['state']]:$usestate;
00464 $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_extensions', $vArr);
00465 }
00466 }
00467 }
00468
00475 function parseMirrorsXML($string) {
00476 global $TYPO3_CONF_VARS;
00477
00478
00479 $parser = xml_parser_create();
00480 $vals = array();
00481 $index = array();
00482
00483 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
00484 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
00485
00486 if ((double)phpversion()>=5) {
00487 $preg_result = array();
00488 preg_match('/^[[:space:]]*<\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/',substr($string,0,200),$preg_result);
00489 $theCharset = $preg_result[1] ? $preg_result[1] : ($TYPO3_CONF_VARS['BE']['forceCharset'] ? $TYPO3_CONF_VARS['BE']['forceCharset'] : 'iso-8859-1');
00490 xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset); // us-ascii / utf-8 / iso-8859-1
00491 }
00492
00493 // Parse content:
00494 xml_parse_into_struct($parser, $string, $vals, $index);
00495
00496 // If error, return error message:
00497 if (xml_get_error_code($parser)) {
00498 $line = xml_get_current_line_number($parser);
00499 $error = xml_error_string(xml_get_error_code($parser));
00500 xml_parser_free($parser);
00501 return 'Error in XML parser while decoding mirrors XML file. Line '.$line.': '.$error;
00502 } else {
00503 // Init vars:
00504 $stack = array(array());
00505 $stacktop = 0;
00506 $mirrornumber = 0;
00507 $current=array();
00508 $tagName = '';
00509 $documentTag = '';
00510
00511 // Traverse the parsed XML structure:
00512 foreach($vals as $val) {
00513
00514 // First, process the tag-name (which is used in both cases, whether "complete" or "close")
00515 $tagName = ($val['tag']=='mirror' && $val['type']=='open') ? '__plh' : $val['tag'];
00516 if (!$documentTag) $documentTag = $tagName;
00517
00518 // Setting tag-values, manage stack:
00519 switch($val['type']) {
00520 case 'open': // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
00521 $current[$tagName] = array(); // Setting blank place holder
00522 $stack[$stacktop++] = $current;
00523 $current = array();
00524 break;
00525 case 'close': // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
00526 $oldCurrent = $current;
00527 $current = $stack[--$stacktop];
00528 end($current); // Going to the end of array to get placeholder key, key($current), and fill in array next:
00529 if($tagName=='mirror') {
00530 unset($current['__plh']);
00531 $current[$oldCurrent['host']] = $oldCurrent;
00532 } else {
00533 $current[key($current)] = $oldCurrent;
00534 }
00535 unset($oldCurrent);
00536 break;
00537 case 'complete': // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
00538 $current[$tagName] = (string)$val['value']; // Had to cast it as a string - otherwise it would be evaluate false if tested with isset()!!
00539 break;
00540 }
00541 }
00542 return $current[$tagName];
00543 }
00544 }
00545
00552 function parseL10nXML($string) {
00553 // Create parser:
00554 $parser = xml_parser_create();
00555 $vals = array();
00556 $index = array();
00557
00558 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
00559 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
00560
00561 // Parse content:
00562 xml_parse_into_struct($parser, $string, $vals, $index);
00563
00564 // If error, return error message:
00565 if (xml_get_error_code($parser)) {
00566 $line = xml_get_current_line_number($parser);
00567 $error = xml_error_string(xml_get_error_code($parser));
00568 debug($error);
00569 xml_parser_free($parser);
00570 return 'Error in XML parser while decoding l10n XML file. Line '.$line.': '.$error;
00571 } else {
00572 // Init vars:
00573 $stack = array(array());
00574 $stacktop = 0;
00575 $mirrornumber = 0;
00576 $current=array();
00577 $tagName = '';
00578 $documentTag = '';
00579
00580 // Traverse the parsed XML structure:
00581 foreach($vals as $val) {
00582
00583 // First, process the tag-name (which is used in both cases, whether "complete" or "close")
00584 $tagName = ($val['tag']=='languagepack' && $val['type']=='open') ? $val['attributes']['language'] : $val['tag'];
00585 if (!$documentTag) $documentTag = $tagName;
00586
00587 // Setting tag-values, manage stack:
00588 switch($val['type']) {
00589 case 'open': // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
00590 $current[$tagName] = array(); // Setting blank place holder
00591 $stack[$stacktop++] = $current;
00592 $current = array();
00593 break;
00594 case 'close': // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
00595 $oldCurrent = $current;
00596 $current = $stack[--$stacktop];
00597 end($current); // Going to the end of array to get placeholder key, key($current), and fill in array next:
00598 $current[key($current)] = $oldCurrent;
00599 unset($oldCurrent);
00600 break;
00601 case 'complete': // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
00602 $current[$tagName] = (string)$val['value']; // Had to cast it as a string - otherwise it would be evaluate false if tested with isset()!!
00603 break;
00604 }
00605 }
00606 return $current[$tagName];
00607 }
00608 }
00609 }
00610 ?>