Documentation TYPO3 par Ameos |
00001 <?php 00002 /* ************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2006 Karsten Dambekalns <karsten@typo3.org> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 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 // show extensions without review or that have passed review 00074 $where.= ' AND reviewstate >= 0'; 00075 } else { 00076 // only display extensions that have passed review 00077 $where.= ' AND reviewstate > 0'; 00078 } 00079 if (!$this->useObsolete && !$allExt) { 00080 $where.= ' AND state!=5'; // 5 == obsolete 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 // Fetch count 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); // Read 64KB 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://www.php.net/manual/en/function.preg-last-error.php" target="_blank">http://www.php.net/manual/en/function.preg-last-error.php</a>'; 00368 $error = true; 00369 break; 00370 } else { 00371 if(gzeof($fp)) break; // Nothing more can be read 00372 $string .= gzread($fp, 0xffff); // Read another 64KB 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; // Extensions without a category end up in "misc" 00437 } else { 00438 if (isset($this->revCatArr[$usecat])) { 00439 $usecat = $this->revCatArr[$usecat]; 00440 } else { 00441 $usecat = 4; // Extensions without a category end up in "misc" 00442 } 00443 } 00444 if (isset($this->revStateArr[$usestate])) { 00445 $usestate = $this->revCatArr[$usestate]; 00446 } else { 00447 $usestate = 999; // Extensions without a category end up in "misc" 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; // 999 = not set category 00464 $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_extensions', $vArr); 00465 } 00466 } 00467 } 00468 00475 function parseMirrorsXML($string) { 00476 global $TYPO3_CONF_VARS; 00477 00478 // Create parser: 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 ?>