TYPO3 API  SVNRelease
class.tx_em_connection_ter.php
Go to the documentation of this file.
00001 <?php
00002 /* **************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 1999-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
00006 *  (c) 2006-2010 Karsten Dambekalns <karsten@typo3.org>
00007 *  All rights reserved
00008 *
00009 *  This script is part of the TYPO3 project. The TYPO3 project is
00010 *  free software; you can redistribute it and/or modify
00011 *  it under the terms of the GNU General Public License as published by
00012 *  the Free Software Foundation; either version 2 of the License, or
00013 *  (at your option) any later version.
00014 *
00015 *  The GNU General Public License can be found at
00016 *  http://www.gnu.org/copyleft/gpl.html.
00017 *  A copy is found in the textfile GPL.txt and important notices to the license
00018 *  from the author is found in LICENSE.txt distributed with these scripts.
00019 *
00020 *
00021 *  This script is distributed in the hope that it will be useful,
00022 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024 *  GNU General Public License for more details.
00025 *
00026 *  This copyright notice MUST APPEAR in all copies of the script!
00027 ***************************************************************/
00028 
00029 
00030 /**
00031  * TER2 connection handling class for the TYPO3 Extension Manager.
00032  *
00033  * It contains methods for downloading and uploading extensions and related code
00034  *
00035  * @author Karsten Dambekalns <karsten@typo3.org>
00036  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00037  * @package TYPO3
00038  * @subpackage EM
00039  */
00040 class tx_em_Connection_Ter {
00041     var $wsdlURL;
00042 
00043     /**
00044      * Extension manager module
00045      *
00046      * @var SC_mod_tools_em_index
00047      */
00048     var $emObj;
00049 
00050     public function __construct($emObj) {
00051         $this->emObj = $emObj;
00052     }
00053 
00054     /**
00055      * Fetches an extension from the given mirror
00056      *
00057      * @param   string      $extKey Extension Key
00058      * @param   string      $version    Version to install
00059      * @param   string      $expectedMD5    Expected MD5 hash of extension file
00060      * @param   string      $mirrorURL  URL of mirror to use
00061      * @return  mixed       T3X data (array) or error message (string)
00062      */
00063     function fetchExtension($extKey, $version, $expectedMD5, $mirrorURL) {
00064         $extPath = t3lib_div::strtolower($extKey);
00065         $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '_' . $version . '.t3x';
00066         $t3x = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
00067         $MD5 = md5($t3x);
00068 
00069         if ($t3x === FALSE) {
00070             return 'The T3X file could not be fetched. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.';
00071         }
00072 
00073         if ($MD5 == $expectedMD5) {
00074             // Fetch and return:
00075             return $this->decodeExchangeData($t3x);
00076         } else {
00077             return 'Error: MD5 hash of downloaded file not as expected:<br />' . $MD5 . ' != ' . $expectedMD5;
00078         }
00079     }
00080 
00081     /**
00082      * Fetches an extensions l10n file from the given mirror
00083      *
00084      * @param string $extKey    Extension Key
00085      * @param string $lang  The language code of the translation to fetch
00086      * @param string $mirrorURL URL of mirror to use
00087      * @return mixed    Array containing l10n data or error message (string)
00088      */
00089     function fetchTranslation($extKey, $lang, $mirrorURL) {
00090         $extPath = t3lib_div::strtolower($extKey);
00091         $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '-l10n/' . $extPath . '-l10n-' . $lang . '.zip';
00092         $l10n = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
00093 
00094         if ($l10n !== false) {
00095             return array($l10n);
00096         } else {
00097             return 'Error: Translation could not be fetched.';
00098         }
00099     }
00100 
00101     /**
00102      * Install translations for all selected languages for an extension
00103      *
00104      * @param string $extKey        The extension key to install the translations for
00105      * @param string $lang      Language code of translation to fetch
00106      * @param string $mirrorURL     Mirror URL to fetch data from
00107      * @return mixed    true on success, error string on fauilure
00108      */
00109     function updateTranslation($extKey, $lang, $mirrorURL) {
00110         $l10n = $this->fetchTranslation($extKey, $lang, $mirrorURL);
00111         if (is_array($l10n)) {
00112             $file = PATH_site . 'typo3temp/' . $extKey . '-l10n-' . $lang . '.zip';
00113             $path = 'l10n/' . $lang . '/';
00114             if (!is_dir(PATH_typo3conf . $path)) {
00115                 t3lib_div::mkdir_deep(PATH_typo3conf, $path);
00116             }
00117             t3lib_div::writeFile($file, $l10n[0]);
00118             if (tx_em_Tools::unzip($file, PATH_typo3conf . $path)) {
00119                 return TRUE;
00120             }
00121         }
00122         return FALSE;
00123     }
00124 
00125     /**
00126      * Fetches extension l10n status from the given mirror
00127      *
00128      * @param string     $extKey    Extension Key
00129      * @param string     $mirrorURL URL of mirror to use
00130      * @return mixed    Array containing l10n status data or FALSE if no status could be fetched
00131      */
00132     function fetchTranslationStatus($extKey, $mirrorURL) {
00133         $extPath = t3lib_div::strtolower($extKey);
00134         $mirrorURL .= $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '-l10n/' . $extPath . '-l10n.xml';
00135         $remote = t3lib_div::getURL($mirrorURL, 0, array(TYPO3_user_agent));
00136 
00137         if ($remote !== false) {
00138             $parsed = $this->emObj->xmlHandler->parseL10nXML($remote);
00139             return $parsed['languagePackIndex'];
00140         }
00141 
00142         return FALSE;
00143     }
00144 
00145     /**
00146      * Decode server data
00147      * This is information like the extension list, extension information etc., return data after uploads (new em_conf)
00148      *
00149      * @param   string      Data stream from remove server
00150      * @return  mixed       On success, returns an array with data array and stats array as key 0 and 1. Otherwise returns error string
00151      * @see fetchServerData(), processRepositoryReturnData()
00152      */
00153     function decodeServerData($externalData) {
00154         $parts = explode(':', $externalData, 4);
00155         $dat = base64_decode($parts[2]);
00156         // compare hashes ignoring any leading whitespace. See bug #0000365.
00157         if (ltrim($parts[0]) == md5($dat)) {
00158             if ($parts[1] == 'gzcompress') {
00159                 if (function_exists('gzuncompress')) {
00160                     $dat = gzuncompress($dat);
00161                 } else {
00162                     return 'Decoding Error: No decompressor available for compressed content. gzuncompress() function is not available!';
00163                 }
00164             }
00165             $listArr = unserialize($dat);
00166 
00167             if (is_array($listArr)) {
00168                 return $listArr;
00169             } else {
00170                 return 'Error: Unserialized information was not an array - strange!';
00171             }
00172         } else {
00173             return 'Error: MD5 hashes in T3X data did not match!';
00174         }
00175     }
00176 
00177     /**
00178      * Decodes extension upload array.
00179      * This kind of data is when an extension is uploaded to TER
00180      *
00181      * @param   string      Data stream
00182      * @return  mixed       Array with result on success, otherwise an error string.
00183      */
00184     function decodeExchangeData($str) {
00185         $parts = explode(':', $str, 3);
00186         if ($parts[1] == 'gzcompress') {
00187             if (function_exists('gzuncompress')) {
00188                 $parts[2] = gzuncompress($parts[2]);
00189             } else {
00190                 return 'Decoding Error: No decompressor available for compressed content. gzcompress()/gzuncompress() functions are not available!';
00191             }
00192         }
00193         if (md5($parts[2]) == $parts[0]) {
00194             $output = unserialize($parts[2]);
00195             if (is_array($output)) {
00196                 return array($output, '');
00197             } else {
00198                 return 'Error: Content could not be unserialized to an array. Strange (since MD5 hashes match!)';
00199             }
00200         } else {
00201             return 'Error: MD5 mismatch. Maybe the extension file was downloaded and saved as a text file by the browser and thereby corrupted!? (Always select "All" filetype when saving extensions)';
00202         }
00203     }
00204 
00205 
00206     /**
00207      * Encodes extension upload array
00208      *
00209      * @param   array       Array containing extension
00210      * @return  string      Content stream
00211      */
00212     function makeUploadDataFromarray($uploadArray) {
00213         $content = '';
00214         if (is_array($uploadArray)) {
00215             $serialized = serialize($uploadArray);
00216             $md5 = md5($serialized);
00217 
00218             $content = $md5 . ':';
00219             $content .= 'gzcompress:';
00220             $content .= gzcompress($serialized);
00221         }
00222         return $content;
00223     }
00224 
00225     /**
00226      * Upload extension to ter
00227      * @param  $em
00228      * @return
00229      */
00230     function uploadToTER($em) {
00231         $uArr = $this->emObj->extensionDetails->makeUploadarray($em['extKey'], $em['extInfo']);
00232         if (!is_array($uArr)) {
00233             return $uArr;
00234         }
00235 
00236         // Render new version number:
00237         $newVersionBase = $em['extInfo']['EM_CONF']['version'];
00238         switch ((string) $em['upload']['mode']) {
00239             case 'new_dev':
00240                 $cmd = 'dev';
00241                 break;
00242             case 'new_sub':
00243                 $cmd = 'sub';
00244                 break;
00245             case 'new_main':
00246                 $cmd = 'main';
00247                 break;
00248             case 'custom':
00249                 $newVersionBase = $em['upload']['version'];
00250             case 'latest':
00251             default:
00252                 $cmd = '';
00253                 break;
00254         }
00255         $versionArr = tx_em_Tools::renderVersion($newVersionBase, $cmd);
00256         $em['version'] = $versionArr['version'];
00257 
00258         // Create dependency / conflict information:
00259         $dependenciesArr = array();
00260         $extKeysArr = $uArr['EM_CONF']['constraints']['depends'];
00261 
00262         if (is_array($extKeysArr)) {
00263             foreach ($extKeysArr as $extKey => $version) {
00264                 if (strlen($extKey)) {
00265                     $dependenciesArr[] = array(
00266                         'kind' => 'depends',
00267                         'extensionKey' => utf8_encode($extKey),
00268                         'versionRange' => utf8_encode($version),
00269                     );
00270                 }
00271             }
00272         }
00273 
00274         $extKeysArr = $uArr['EM_CONF']['constraints']['conflicts'];
00275         if (is_array($extKeysArr)) {
00276             foreach ($extKeysArr as $extKey => $version) {
00277                 if (strlen($extKey)) {
00278                     $dependenciesArr[] = array(
00279                         'kind' => 'conflicts',
00280                         'extensionKey' => utf8_encode($extKey),
00281                         'versionRange' => utf8_encode($version),
00282                     );
00283                 }
00284             }
00285         }
00286         // FIXME: This part must be removed, when the problem is solved on the TER-Server #5919
00287         if (count($dependenciesArr) == 1) {
00288             $dependenciesArr[] = array(
00289                 'kind' => 'depends',
00290                 'extensionKey' => '',
00291                 'versionRange' => '',
00292             );
00293         }
00294         // END for Bug #5919
00295 
00296         // Compile data for SOAP call:
00297         $accountData = array(
00298             'username' => $em['user']['fe_u'],
00299             'password' => $em['user']['fe_p']
00300         );
00301         $extensionData = array(
00302             'extensionKey' => utf8_encode($em['extKey']),
00303             'version' => utf8_encode($em['version']),
00304             'metaData' => array(
00305                 'title' => utf8_encode($uArr['EM_CONF']['title']),
00306                 'description' => utf8_encode($uArr['EM_CONF']['description']),
00307                 'category' => utf8_encode($uArr['EM_CONF']['category']),
00308                 'state' => utf8_encode($uArr['EM_CONF']['state']),
00309                 'authorName' => utf8_encode($uArr['EM_CONF']['author']),
00310                 'authorEmail' => utf8_encode($uArr['EM_CONF']['author_email']),
00311                 'authorCompany' => utf8_encode($uArr['EM_CONF']['author_company']),
00312             ),
00313             'technicalData' => array(
00314                 'dependencies' => $dependenciesArr,
00315                 'loadOrder' => utf8_encode($uArr['EM_CONF']['loadOrder']),
00316                 'uploadFolder' => (boolean) intval($uArr['EM_CONF']['uploadfolder']),
00317                 'createDirs' => utf8_encode($uArr['EM_CONF']['createDirs']),
00318                 'shy' => (boolean) intval($uArr['EM_CONF']['shy']),
00319                 'modules' => utf8_encode($uArr['EM_CONF']['module']),
00320                 'modifyTables' => utf8_encode($uArr['EM_CONF']['modify_tables']),
00321                 'priority' => utf8_encode($uArr['EM_CONF']['priority']),
00322                 'clearCacheOnLoad' => (boolean) intval($uArr['EM_CONF']['clearCacheOnLoad']),
00323                 'lockType' => utf8_encode($uArr['EM_CONF']['lockType']),
00324                 'doNotLoadInFEe' => utf8_encode($uArr['EM_CONF']['doNotLoadInFE']),
00325                 'docPath' => utf8_encode($uArr['EM_CONF']['docPath']),
00326             ),
00327             'infoData' => array(
00328                 'codeLines' => intval($uArr['misc']['codelines']),
00329                 'codeBytes' => intval($uArr['misc']['codebytes']),
00330                 'codingGuidelinesCompliance' => utf8_encode($uArr['EM_CONF']['CGLcompliance']),
00331                 'codingGuidelinesComplianceNotes' => utf8_encode($uArr['EM_CONF']['CGLcompliance_note']),
00332                 'uploadComment' => utf8_encode($em['upload']['comment']),
00333                 'techInfo' => $uArr['techInfo'],
00334             ),
00335         );
00336 
00337         $filesData = array();
00338         foreach ($uArr['FILES'] as $filename => $infoArr) {
00339             $filesData[] = array(
00340                 'name' => utf8_encode($infoArr['name']),
00341                 'size' => intval($infoArr['size']),
00342                 'modificationTime' => intval($infoArr['mtime']),
00343                 'isExecutable' => intval($infoArr['is_executable']),
00344                 'content' => $infoArr['content'],
00345                 'contentMD5' => $infoArr['content_md5'],
00346             );
00347         }
00348 
00349         $soap = t3lib_div::makeInstance('tx_em_Connection_Soap');
00350         $soap->init(array('wsdl' => $this->wsdlURL, 'soapoptions' => array('trace' => 1, 'exceptions' => 0)));
00351         $response = $soap->call(
00352             'uploadExtension',
00353             array(
00354                 'accountData' => $accountData,
00355                 'extensionData' => $extensionData,
00356                 'filesData' => $filesData
00357             )
00358         );
00359 
00360         if ($response === FALSE) {
00361             switch (TRUE) {
00362                 case is_string($soap->error):
00363                     return $soap->error;
00364                     break;
00365                 default:
00366                     return $soap->error->faultstring;
00367             }
00368         }
00369 
00370         return $response;
00371     }
00372 }
00373 
00374 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/connection/class.tx_em_connection_ter.php'])) {
00375     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/connection/class.tx_em_connection_ter.php']);
00376 }
00377 ?>