The EM now stores the list of extensions from TER in the database, see http://bugs...
authorKarsten Dambekalns <karsten.dambekalns@typo3.org>
Tue, 12 Dec 2006 11:57:52 +0000 (11:57 +0000)
committerKarsten Dambekalns <karsten.dambekalns@typo3.org>
Tue, 12 Dec 2006 11:57:52 +0000 (11:57 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@1869 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/stddb/tables.sql
typo3/mod/tools/em/class.em_index.php
typo3/mod/tools/em/class.em_unzip.php
typo3/mod/tools/em/class.em_xmlhandler.php

index 09e918a..a9bafff 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-12-12  Karsten Dambekalns  <karsten@typo3.org>
+
+       * The EM now stores the list of extensions from TER in the database, see http://bugs.typo3.org/view.php?id=2615
+
 2006-12-12  Ingmar Schlecht  <ingmar@typo3.org>
 
        * Better getRecordTitle() function introducing label_userFunc (Thanks to David Brühlmeier for this patch! See http://lists.netfielders.de/pipermail/typo3-team-core/2006-December/006521.html for details.)
index df31533..2bf44d0 100755 (executable)
@@ -96,6 +96,33 @@ CREATE TABLE be_users (
 );
 
 #
+# 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 (
index 55a65b3..2fc9e4b 100644 (file)
@@ -201,6 +201,8 @@ class SC_mod_tools_em_index extends t3lib_SCbase {
        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
@@ -763,18 +765,25 @@ EXTENSION KEYS:
                        $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']]))   {
@@ -817,9 +826,11 @@ EXTENSION KEYS:
                                                                }
 
                                                                $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/>');
@@ -827,10 +838,13 @@ EXTENSION KEYS:
                                        $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;
 
@@ -886,7 +900,7 @@ EXTENSION KEYS:
                                $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;
@@ -914,6 +928,29 @@ EXTENSION KEYS:
                $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
@@ -1334,9 +1371,8 @@ EXTENSION KEYS:
                $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;
@@ -1427,8 +1463,7 @@ EXTENSION KEYS:
                                                $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;
@@ -1543,10 +1578,10 @@ EXTENSION KEYS:
                        // 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])) {
@@ -1668,7 +1703,7 @@ EXTENSION KEYS:
                                } 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)) {
@@ -3065,9 +3100,10 @@ EXTENSION KEYS:
        /**
         * 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();
@@ -3098,6 +3134,9 @@ EXTENSION KEYS:
                                );
                        }
                        $this->setCat($cat, $list[$extKey]['versions'][$version], $extKey);
+                       if ($unsetProc) {
+                               unset($this->xmlhandler->extensionsXML[$extKey]);
+                       }
                }
 
                return array($list,$cat);
@@ -4920,7 +4959,7 @@ $EM_CONF[$_EXTKEY] = '.$this->arrayToCode($EM_CONF, 0).';
 
                $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];
index 2c03cb9..4a1ee7c 100644 (file)
@@ -507,6 +507,7 @@ class em_unzip {
                $v_result=1;
 
                // Read the file header
+               $v_header = '';
                if (($v_result = $this->_readFileHeader($v_header)) != 1)
                {
                        // Return
index 7a274f2..75ce2a0 100644 (file)
@@ -56,51 +56,86 @@ class SC_mod_tools_em_xmlhandler {
         * @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'];
                        }
-               }
-       }
-
-       /**
-        * 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;
-       }
+                       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);
+       }
+
+       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
@@ -108,38 +143,7 @@ class SC_mod_tools_em_xmlhandler {
         * @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;
-               }
-       }
-
-       /**
-        * 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)));
+               $this->searchExtensionsXML('', '', '', true);
        }
 
        /**
@@ -169,20 +173,20 @@ class SC_mod_tools_em_xmlhandler {
        }
 
        /**
-        * 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;
        }
 
        /**
@@ -195,7 +199,7 @@ class SC_mod_tools_em_xmlhandler {
                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]);
                }
@@ -301,36 +305,160 @@ class SC_mod_tools_em_xmlhandler {
         * @param       string          XML data file to parse
         * @return      string          HTLML output informing about result
         */
-       function parseExtensionsXML($string) {
-               global $TYPO3_CONF_VARS;
+       function parseExtensionsXML($filename) {
 
                $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
         *