Project

General

Profile

Bug #15663 » EM_MemFix_2006-12-11_SVNrev1860.diff

Administrator Admin, 2006-12-11 23:10

View differences:

t3lib/stddb/tables.sql (working copy)
);
#
# Table structure for table 'cache_extensions'
#
CREATE TABLE cache_extensions (
extkey varchar(60) NOT NULL default '',
version varchar(10) NOT NULL default '',
alldownloadcounter int(11) unsigned NOT NULL default '0',
downloadcounter int(11) unsigned NOT NULL default '0',
title varchar(150) NOT NULL default '',
description mediumtext NOT NULL,
state int(4) NOT NULL default '0',
reviewstate int(4) unsigned NOT NULL default '0',
category int(4) NOT NULL default '0',
lastuploaddate int(11) unsigned NOT NULL default '0',
dependencies mediumtext NOT NULL,
authorname varchar(100) NOT NULL default '',
authoremail varchar(100) NOT NULL default '',
ownerusername varchar(50) NOT NULL default '',
t3xfilemd5 varchar(35) NOT NULL default '',
uploadcomment mediumtext NOT NULL,
authorcompany varchar(100) NOT NULL default '',
intversion int(11) NOT NULL default '0',
lastversion int(3) NOT NULL default '0',
lastreviewedversion int(3) NOT NULL default '0',
PRIMARY KEY (extkey,version)
);
#
# Table structure for table 'cache_hash'
#
CREATE TABLE cache_hash (
typo3/mod/tools/em/class.em_unzip.php (working copy)
$v_result=1;
// Read the file header
$v_header = '';
if (($v_result = $this->_readFileHeader($v_header)) != 1)
{
// Return
typo3/mod/tools/em/class.em_index.php (working copy)
var $maxUploadSize = 31457280; // Max size in bytes of extension upload to repository
var $kbMax = 500; // Max size in kilobytes for files to be edited.
var $doPrintContent = true; // If set (default), the function printContent() will echo the content which was collected in $this->content. You can set this to FALSE in order to echo content from elsewhere, fx. when using outbut buffering
var $listingLimit = 500; // List that many extension maximally at one time (fixing memory problems)
var $listingLimitAuthor = 250; // List that many extension maximally at one time (fixing memory problems)
/**
* Internal variable loaded with extension categories (for display/listing). Should reflect $categories above
......
$this->detailCols[1]+=6;
// see if we have an extensionlist at all
$this->xmlhandler->loadExtensionsXML();
if (!count($this->xmlhandler->extensionsXML)) {
$this->extensionCount = $this->xmlhandler->countExtensions();
if (!$this->extensionCount) {
$content .= $this->fetchMetaData('extensions');
}
if($this->MOD_SETTINGS['listOrder']=='author_company') {
$this->listingLimit = $this->listingLimitAuthor;
}
$this->pointer = intval(t3lib_div::_GP('pointer'));
$offset = $this->listingLimit*$this->pointer;
if($this->MOD_SETTINGS['display_own'] && strlen($this->fe_user['username'])) {
$this->xmlhandler->searchExtensionsXML($this->listRemote_search, $this->fe_user['username']);
$this->xmlhandler->searchExtensionsXML($this->listRemote_search, $this->fe_user['username'], $this->MOD_SETTINGS['listOrder']);
} else {
$this->xmlhandler->searchExtensionsXML($this->listRemote_search);
$this->xmlhandler->searchExtensionsXML($this->listRemote_search, '', $this->MOD_SETTINGS['listOrder'], false, false, $offset, $this->listingLimit);
}
if (count($this->xmlhandler->extensionsXML)) {
list($list,$cat) = $this->prepareImportExtList();
list($list,$cat) = $this->prepareImportExtList(true);
// Available extensions
if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
......
}
$lines[]=$this->extensionListRow($extKey,$ext,array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.rawurlencode($extKey));
unset($list[$extKey]);
}
}
}
unset($list);
// CSH:
$content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>');
......
$content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions<br />
<input type="text" name="_lookUp" value="'.htmlspecialchars($this->listRemote_search).'" /> <input type="submit" value="Look up" /><br /><br />';
$content .= $this->browseLinks();
$content.= '
<!-- TER Extensions list -->
<table border="0" cellpadding="2" cellspacing="1">'.implode(chr(10),$lines).'</table>';
$content .= '<br />'.$this->browseLinks();
$content.= '<br /><br />'.$this->securityHint;
$content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice;
......
$content.= 'Connect to the current mirror and retrieve the current list of available plugins from the TYPO3 Extension Repository.<br />
<input type="submit" value="Retrieve/Update" onclick="'.htmlspecialchars($onCLick).'" />';
if(is_file(PATH_site.'typo3temp/extensions.bin')) {
$content .= ' (last update: '.date('Y-m-d H:i',filemtime(PATH_site.'typo3temp/extensions.bin')).')';
$content .= ' (last update: '.date('Y-m-d H:i',filemtime(PATH_site.'typo3temp/extensions.xml.gz')).')';
}
}
$content.= '<br /><br />'.$this->securityHint;
......
$this->content.=$this->doc->spacer(20);
$this->content.=$this->doc->section('Upload extension file directly (.t3x):',$content,0,1);
}
/**
* Generates a link to the next page of extensions
*
* @return void
*/
function browseLinks() {
$content = '';
if ($this->pointer) {
$content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer-1)).'" class="typo3-prevPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilleft_n.gif','width="14" height="14"').' alt="Prev page" /> Prev page</a>';
}
if ($content) $content .= '&nbsp;&nbsp;&nbsp;';
if (intval($this->xmlhandler->matchingCount/$this->listingLimit)>$this->pointer) {
$content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer+1)).'" class="typo3-nextPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilright_n.gif','width="14" height="14"').' alt="Next page" /> Next page</a>';
}
$upper = (($this->pointer+1)*$this->listingLimit);
if ($upper>$this->xmlhandler->matchingCount) {
$upper = $this->xmlhandler->matchingCount;
}
if ($content) $content .= '<br /><br />Showing extensions <strong>'.($this->pointer*$this->listingLimit+1).'</strong> to <strong>'.$upper.'</strong>';
if ($content) $content .= '<br /><br />';
return $content;
}
/**
* Allows changing of settings
......
$content = '';
// Fetch remote data:
$this->xmlhandler->loadExtensionsXML();
$this->xmlhandler->extensionsXML = array($extKey => $this->xmlhandler->extensionsXML[$extKey]);
list($fetchData,) = $this->prepareImportExtList();
$this->xmlhandler->searchExtensionsXML($extKey, '', '', true, true);
list($fetchData,) = $this->prepareImportExtList(true);
$versions = array_keys($fetchData[$extKey]['versions']);
$version = ($version == '') ? end($versions) : $version;
......
$content .= '<p>Error: The extension list could not be fetched from '.$extfile.'. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>';
} else {
t3lib_div::writeFile(PATH_site.'typo3temp/extensions.xml.gz', $extXML);
$content .= $this->xmlhandler->parseExtensionsXML(implode('',gzfile(PATH_site.'typo3temp/extensions.xml.gz')));
$this->xmlhandler->saveExtensionsXML();
$content .= $this->xmlhandler->parseExtensionsXML(PATH_site.'typo3temp/extensions.xml.gz');
}
}
break;
......
// at this point we know we need to import (a matching version of) the extension from TER2
// see if we have an extensionlist at all
$this->xmlhandler->loadExtensionsXML();
if (!count($this->xmlhandler->extensionsXML)) {
if (!$this->xmlhandler->countExtensions()) {
$this->fetchMetaData('extensions');
}
$this->xmlhandler->searchExtensionsXML($extKey, '', '', true);
// check if extension can be fetched
if(isset($this->xmlhandler->extensionsXML[$extKey])) {
......
} else return 'Wrong file format. No data recognized, '.$fetchData;
} else return 'No file uploaded! Probably the file was too large for PHPs internal limit for uploadable files.';
} else {
$this->xmlhandler->loadExtensionsXML();
$this->xmlhandler->searchExtensionsXML($extKey, '', '', true);
// Fetch extension from TER:
if(!strlen($version)) {
......
/**
* Maps remote extensions information into $cat/$list arrays for listing
*
* @param boolean If set the info in the internal extensionsXML array will be unset before returning the result.
* @return array List array and category index as key 0 / 1 in an array.
*/
function prepareImportExtList() {
function prepareImportExtList($unsetProc = false) {
$list = array();
$cat = $this->defaultCategories;
$filepath = $this->getMirrorURL();
......
);
}
$this->setCat($cat, $list[$extKey]['versions'][$version], $extKey);
if ($unsetProc) {
unset($this->xmlhandler->extensionsXML[$extKey]);
}
}
return array($list,$cat);
}
......
$res = array();
$res['version'] = $parts[0].'.'.$parts[1].'.'.$parts[2];
$res['version_int'] = intval(str_pad($parts[0],3,'0',STR_PAD_LEFT).str_pad($parts[1],3,'0',STR_PAD_LEFT).str_pad($parts[2],3,'0',STR_PAD_LEFT));
$res['version_int'] = intval($parts[0]*1000000+$parts[1]*1000+$parts[2]);
$res['version_main'] = $parts[0];
$res['version_sub'] = $parts[1];
$res['version_dev'] = $parts[2];
typo3/mod/tools/em/class.em_xmlhandler.php (working copy)
* @param boolean $latest If true, only the latest version is kept in the list
* @return [type] ...
*/
function searchExtensionsXML($search, $owner='') {
if(!count($this->extensionsXML)) $this->loadExtensionsXML();
reset($this->extensionsXML);
while (list($extkey, $data) = each($this->extensionsXML)) {
// Unset extension key in installed keys array (for tracking)
if(isset($this->emObj->inst_keys[$extkey])) unset($this->emObj->inst_keys[$extkey]);
if(strlen($search) && !stristr($extkey,$search)) {
unset($this->extensionsXML[$extkey]);
continue;
function searchExtensionsXML($search, $owner='', $order = '', $allExt = false, $allVer = false, $offset = 0, $limit = 500) {
$where = '1=1';
if ($search) {
$where .= ' AND extkey LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($GLOBALS['TYPO3_DB']->escapeStrForLike($search, 'cache_extensions'), 'cache_extensions').'%\'';
}
if ($owner) {
$where .= ' AND ownerusername='.$GLOBALS['TYPO3_DB']->fullQuoteStr($owner, 'cache_extensions');
}
if(!(strlen($owner) || $this->useUnchecked || $allExt)) {
$where .= ' AND reviewstate>0';
}
if(!($this->useObsolete || $allExt)) {
$where .= ' AND state!=5'; // 5 == obsolete
}
switch ($order) {
case 'author_company':
$forder = 'authorname, authorcompany';
break;
case 'state':
$forder = 'state';
break;
case 'cat':
default:
$forder = 'category';
break;
}
$order = $forder.', title';
if (!$allVer) {
if ($this->useUnchecked) {
$where .= ' AND lastversion>0';
} else {
$where .= ' AND lastreviewedversion>0';
}
}
$this->catArr = array();
$idx = 0;
foreach ($this->emObj->defaultCategories['cat'] as $catKey => $tmp) {
$this->catArr[$idx] = $catKey;
$idx++;
}
$this->stateArr = array();
$idx = 0;
foreach ($this->emObj->states as $state => $tmp) {
$this->stateArr[$idx] = $state;
$idx++;
}
if(strlen($owner) && !$this->checkOwner($extkey, $owner)) {
unset($this->extensionsXML[$extkey]);
continue;
}
// Fetch count
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*) as cnt', 'cache_extensions', $where, '', $order);
$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
$this->matchingCount = $row['cnt'];
$GLOBALS['TYPO3_DB']->sql_free_result($res);
if(!strlen($owner)) {
$this->checkReviewState($this->extensionsXML[$extkey]['versions']); // if showing only own extensions, never hide unreviewed
}
$this->removeObsolete($this->extensionsXML[$extkey]['versions']);
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*) as cnt', 'cache_extensions', $where, '', $order);
uksort($data['versions'], array($this->emObj, 'versionDifference')); // needed? or will the extensions always be sorted in the XML anyway? Robert?
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'cache_extensions', $where, '', $order, $offset.','.$limit);
$this->extensionsXML = array();
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
$row['category'] = $this->catArr[$row['category']];
$row['state'] = $this->stateArr[$row['state']];
if(!count($this->extensionsXML[$extkey]['versions'])) {
unset($this->extensionsXML[$extkey]);
if (!is_array($this->extensionsXML[$row['extkey']])) {
$this->extensionsXML[$row['extkey']] = array();
$this->extensionsXML[$row['extkey']]['downloadcounter'] = $row['alldownloadcounter'];
}
}
}
if (!is_array($this->extensionsXML[$row['extkey']]['versions'])) {
$this->extensionsXML[$row['extkey']]['versions'] = array();
}
$row['dependencies'] = unserialize($row['dependencies']);
$this->extensionsXML[$row['extkey']]['versions'][$row['version']] = $row;
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
}
/**
* Checks whether at least one of the extension versions is owned by the given username
*
* @param string $extkey
* @param string $owner
* @return boolean
*/
function checkOwner($extkey, $owner) {
foreach($this->extensionsXML[$extkey]['versions'] as $ext) {
if($ext['ownerusername'] == $owner) return true;
}
return false;
}
function countExtensions() {
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('extkey', 'cache_extensions', '1=1', 'extkey');
$cnt = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
$GLOBALS['TYPO3_DB']->sql_free_result($res);
return $cnt;
}
/**
* Loads the pre-parsed extension list
......
* @return boolean true on success, false on error
*/
function loadExtensionsXML() {
if(is_file(PATH_site.'typo3temp/extensions.bin')) {
$this->extensionsXML = unserialize(gzuncompress(t3lib_div::getURL(PATH_site.'typo3temp/extensions.bin')));
return true;
} else {
$this->extensionsXML = array();
return false;
}
$this->searchExtensionsXML('', '', '', true);
}
/**
* Loads the pre-parsed extension list
*
* @return boolean true on success, false on error
*/
function loadReviewStates() {
if(is_file(PATH_site.'typo3temp/reviewstates.bin')) {
$this->reviewStates = unserialize(gzuncompress(t3lib_div::getURL(PATH_site.'typo3temp/reviewstates.bin')));
return true;
} else {
$this->reviewStates = array();
return false;
}
}
/**
* Enter description here...
*
* @return [type] ...
*/
function saveExtensionsXML() {
t3lib_div::writeFile(PATH_site.'typo3temp/extensions.bin',gzcompress(serialize($this->extXMLResult)));
t3lib_div::writeFile(PATH_site.'typo3temp/reviewstates.bin',gzcompress(serialize($this->reviewStates)));
}
/**
* Frees the pre-parsed extension list
*
* @return void
......
}
/**
* Enter description here...
+ * Returns the reviewstate of a specific extension-key/version
*
* @param string $extKey
* @param string $version: ...
* @return integer Review state, if none is set 0 is returned as default.
*/
function getReviewState($extKey, $version) {
if(!is_array($this->reviewStates)) $this->loadReviewStates();
if(isset($this->reviewStates[$extKey])) {
return (int)$this->reviewStates[$extKey][$version];
} else {
return 0;
}
$where = 'extkey='.$GLOBALS['TYPO3_DB']->fullQuoteStr($extKey, 'cache_extensions').' AND version='.$GLOBALS['TYPO3_DB']->fullQuoteStr($version, 'cache_extensions');
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('reviewstate', 'cache_extensions', $where);
if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
return $row['reviewstate'];
}
$GLOBALS['TYPO3_DB']->sql_free_result($res);
return 0;
}
/**
......
if ($this->useUnchecked) return;
reset($extensions);
while (list($version, $data) = each($extensions)) {
while (list($version, $data) = each($extensions)) {
if($data['reviewstate']<1)
unset($extensions[$version]);
}
......
* @param string XML data file to parse
* @return string HTLML output informing about result
*/
function parseExtensionsXML($string) {
function parseExtensionsXML($filename) {
global $TYPO3_CONF_VARS;
$parser = xml_parser_create();
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'utf-8');
xml_set_element_handler($parser, array(&$this,'startElement'), array(&$this,'endElement'));
xml_set_character_data_handler($parser, array(&$this,'characterData'));
if ((double)phpversion()>=5) {
$preg_result = array();
preg_match('/^[[:space:]]*<\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/',substr($string,0,200),$preg_result);
$theCharset = $preg_result[1] ? $preg_result[1] : ($TYPO3_CONF_VARS['BE']['forceCharset'] ? $TYPO3_CONF_VARS['BE']['forceCharset'] : 'iso-8859-1');
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset); // us-ascii / utf-8 / iso-8859-1
$fp = gzopen($filename, 'rb');
if (!$fp) {
$content.= 'Error opening XML extension file "'.$filename.'"';
return $content;
}
$string = gzread($fp, 0xffff); // Read 64KB
// Parse content:
if (!xml_parse($parser, $string)) {
$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));
$error = true;
$this->revCatArr = array();
$idx = 0;
foreach ($this->emObj->defaultCategories['cat'] as $catKey => $tmp) {
$this->revCatArr[$catKey] = $idx++;
}
$this->revStateArr = array();
$idx = 0;
foreach ($this->emObj->states as $state => $tmp) {
$this->revStateArr[$state] = $idx++;
}
$GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', '1=1');
$extcount = 0;
@ini_set('pcre.backtrack_limit', 500000);
do {
if (preg_match('/.*(<extension\s+extensionkey="[^"]+">.*<\/extension>)/suU', $string, $match)) {
// Parse content:
if (!xml_parse($parser, $match[0], 0)) {
$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));
$error = true;
break;
}
$this->storeXMLResult();
$this->extXMLResult = array();
$extcount++;
$string = substr($string, strlen($match[0]));
} elseif(function_exists('preg_last_error') && preg_last_error()) {
$errorcodes = array(
0 => 'PREG_NO_ERROR',
1 => 'PREG_INTERNAL_ERROR',
2 => 'PREG_BACKTRACK_LIMIT_ERROR',
3 => 'PREG_RECURSION_LIMIT_ERROR',
4 => 'PREG_BAD_UTF8_ERROR'
);
$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>';
$error = true;
break;
} else {
if(gzeof($fp)) break; // Nothing more can be read
$string .= gzread($fp, 0xffff); // Read another 64KB
}
} while (true);
xml_parser_free($parser);
gzclose($fp);
if(!$error) {
$content.= '<p>The extensions list has been updated and now contains '.count($this->extXMLResult).' extension entries.</p>';
$content.= '<p>The extensions list has been updated and now contains '.$extcount.' extension entries.</p>';
}
return $content;
}
function storeXMLResult() {
foreach ($this->extXMLResult as $extkey => $extArr) {
$max = -1;
$maxrev = -1;
$last = '';
$lastrev = '';
$usecat = '';
$usetitle = '';
$usestate = '';
$useauthorcompany = '';
$useauthorname = '';
$verArr = array();
foreach ($extArr['versions'] as $version => $vArr) {
$iv = $this->emObj->makeVersion($version, 'int');
if ($vArr['title']&&!$usetitle) {
$usetitle = $vArr['title'];
}
if ($vArr['state']&&!$usestate) {
$usestate = $vArr['state'];
}
if ($vArr['authorcompany']&&!$useauthorcompany) {
$useauthorcompany = $vArr['authorcompany'];
}
if ($vArr['authorname']&&!$useauthorname) {
$useauthorname = $vArr['authorname'];
}
$verArr[$version] = $iv;
if ($iv>$max) {
$max = $iv;
$last = $version;
if ($vArr['title']) {
$usetitle = $vArr['title'];
}
if ($vArr['state']) {
$usestate = $vArr['state'];
}
if ($vArr['authorcompany']) {
$useauthorcompany = $vArr['authorcompany'];
}
if ($vArr['authorname']) {
$useauthorname = $vArr['authorname'];
}
$usecat = $vArr['category'];
}
if ($vArr['reviewstate'] && ($iv>$maxrev)) {
$maxrev = $iv;
$lastrev = $version;
}
}
if (!strlen($usecat)) {
$usecat = 4; // Extensions without a category end up in "misc"
} else {
if (isset($this->revCatArr[$usecat])) {
$usecat = $this->revCatArr[$usecat];
} else {
$usecat = 4; // Extensions without a category end up in "misc"
}
}
if (isset($this->revStateArr[$usestate])) {
$usestate = $this->revCatArr[$usestate];
} else {
$usestate = 999; // Extensions without a category end up in "misc"
}
foreach ($extArr['versions'] as $version => $vArr) {
$vArr['version'] = $version;
$vArr['intversion'] = $verArr[$version];
$vArr['extkey'] = $extkey;
$vArr['alldownloadcounter'] = $extArr['downloadcounter'];
$vArr['dependencies'] = serialize($vArr['dependencies']);
$vArr['category'] = $usecat;
$vArr['title'] = $usetitle;
if ($version==$last) {
$vArr['lastversion'] = 1;
}
if ($version==$lastrev) {
$vArr['lastreviewedversion'] = 1;
}
$vArr['state'] = isset($this->revStateArr[$vArr['state']])?$this->revStateArr[$vArr['state']]:$usestate; // 999 = not set category
$GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_extensions', $vArr);
}
}
}
/**
* Parses content of mirrors.xml into a suitable array
*
(8-8/8)