#!/usr/bin/php
<?php
/***************************************************************
*  Copyright notice
*
*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*  A copy is found in the textfile GPL.txt and important notices to the license
*  from the author is found in LICENSE.txt distributed with these scripts.
*
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
  * Extract an {ExtensionKey}.t3x file into currentDirectory/extensionKey
  *
  * USAGE: windows
  *     php t3x.php T3X_tt_news-2_5_0-2007-10-08.t3x
  * USAGE: linux
  *        t3x.php T3X_tt_news-2_5_0-2007-10-08.t3x
  *
  * NOTE: multiple parts of this code come from :
  *     class.em_index.php,
  *     class.t3lib_div.php,
  *     class.em_erconnection.php
  *
  * @author    Christophe <Christophe@devethic.com>
  */

     /**
      * Compiles the ext_emconf.php file
      *
      * @param    string        Extension key
      * @param    array        EM_CONF array
      * @return    string        PHP file content, ready to write to ext_emconf.php file
      */
     function construct_ext_emconf_file($extKey,$EM_CONF)    {

         $code = '<?php

########################################################################
# Extension Manager/Repository config file for ext: "'.$extKey.'"
#
# Auto generated '.date('d-m-Y H:i').'
#
# Manual updates:
# Only the data in the array - anything else is removed by next write.
# "version" and "dependencies" must not be touched!
########################################################################

$EM_CONF[$_EXTKEY] = '.arrayToCode($EM_CONF, 0).';

?>';
         return str_replace(chr(13), '', $code);
     }

     /**
      * Enter description here...
      *
      * @param    unknown_type        $array
      * @param    unknown_type        $lines
      * @param    unknown_type        $level
      * @return    unknown
      */
     function arrayToCode($array, $level=0) {
         $lines = 'array('.chr(10);
         $level++;
         foreach($array as $k => $v)    {
             if(strlen($k) && is_array($v)) {
                 $lines .= str_repeat(chr(9),$level)."'".$k."' => ".arrayToCode($v, $level);
             } elseif(strlen($k)) {
                 $lines .= str_repeat(chr(9),$level)."'".$k."' => ".(testInt($v) ? intval($v) : "'".slashJS(trim($v),1)."'").','.chr(10);
             }
         }

         $lines .= str_repeat(chr(9),$level-1).')'.($level-1==0 ? '':','.chr(10));
         return $lines;
     }

     /**
      * This function is used to escape any ' -characters when transferring text to JavaScript!
      * Usage: 3
      *
      * @param    string        String to escape
      * @param    boolean        If set, also backslashes are escaped.
      * @param    string        The character to escape, default is ' (single-quote)
      * @return    string        Processed input string
      */
     function slashJS($string,$extended=0,$char="'")    {
         if ($extended)    {$string = str_replace ("\\", "\\\\", $string);}
         return str_replace ($char, "\\".$char, $string);
     }

     /**
      * Tests if the input is an integer.
      * Usage: 77
      *
      * @param    mixed        Any input variable to test.
      * @return    boolean        Returns true if string is an integer
      */
     function testInt($var)    {
         return !strcmp($var,intval($var));
     }

     /**
      * Extracts the directories in the $files array
      *
      * @param    array        Array of files / directories
      * @return    array        Array of directories from the input array.
      */
     function extractDirsFromFileList($files)    {
         $dirs = array();

         if (is_array($files))    {
             // Traverse files / directories array:
             foreach($files as $file)    {
                 if (substr($file,-1)=='/')    {
                     $dirs[$file] = $file;
                 } else {
                     $pI = pathinfo($file);
                     if (strcmp($pI['dirname'],'') && strcmp($pI['dirname'],'.'))    {
                         $dirs[$pI['dirname'].'/'] = $pI['dirname'].'/';
                     }
                 }
             }
         }
         return $dirs;
     }

     /**
      * Creates directories in $extDirPath
      *
      * @param    array        Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc...
      * @param    string        Absolute path to directory.
      * @return    mixed        Returns false on success or an error string
      */
     function createDirsInPath($dirs,$extDirPath)    {
         if (is_array($dirs))    {
             foreach($dirs as $dir)    {
                 $error = mkdir_deep($extDirPath,$dir);
                 if ($error)    return $error;
             }
         }

         return false;
     }


     /**
      * Creates a directory - including parent directories if necessary - in the file system
      *
      * @param    string        Base folder. This must exist! Must have trailing slash! Example "/root/typo3site/"
      * @param    string        Deep directory to create, eg. "xx/yy/" which creates "/root/typo3site/xx/yy/" if $destination is "/root/typo3site/"
      * @return    string        If error, returns error string.
      */
     function mkdir_deep($destination,$deepDir)    {
         $allParts = trimExplode('/',$deepDir,1);
         $root = '';
         foreach($allParts as $part)    {
             $root.= $part.'/';
             if (!is_dir($destination.$root))    {
                 mkdir($destination.$root);
                 if (!@is_dir($destination.$root))    {
                     return 'Error: The directory "'.$destination.$root.'" could not be created...';
                 }
             }
         }
     }

     /**
      * Writes $content to the file $file
      * Usage: 30
      *
      * @param    string        Filepath to write to
      * @param    string        Content to write
      * @return    boolean        True if the file was successfully opened and written to.
      */
     function writeFile($file,$content)    {
         if (!@is_file($file))    $changePermissions = true;

         if ($fd = fopen($file,'wb'))    {
             $res = fwrite($fd,$content);
             fclose($fd);

             if ($res===false)    return false;

             if ($changePermissions)    {    // Change the permissions only if the file has just been created
                 fixPermissions($file);
             }

             return true;
         }

         return false;
     }

     /**
      * Setting file system mode & group ownership of file
      *
      * @param    string        Filepath of newly created file
      * @return    void
      */
     function fixPermissions($file)    {
         if (@is_file($file) && TYPO3_OS!='WIN')    {
             @chmod($file, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask']));        // "@" is there because file is not necessarily OWNED by the user
             if($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'])    {    // skip this if createGroup is empty
                 @chgrp($file, $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']);        // "@" is there because file is not necessarily OWNED by the user
             }
         }
     }

     /**
      * Explodes a string and trims all values for whitespace in the ends.
      * If $onlyNonEmptyValues is set, then all blank ('') values are removed.
      * Usage: 256
      *
      * @param    string        Delimiter string to explode with
      * @param    string        The string to explode
      * @param    boolean        If set, all empty values (='') will NOT be set in output
      * @return    array        Exploded values
      */
     function trimExplode($delim, $string, $onlyNonEmptyValues=0)    {
         $temp = explode($delim,$string);
         $newtemp=array();
         while(list($key,$val)=each($temp))    {
             if (!$onlyNonEmptyValues || strcmp('',trim($val)))    {
                 $newtemp[]=trim($val);
             }
         }
         reset($newtemp);
         return $newtemp;
     }


#--END FUNCTIONS DECLARATION-----------------------------------------------------------------------------

     if ($argc != 2) {
         echo 'Usage: t3x.php "fichier.t3x"';
         exit;
     }

     // get file content
     $str = file_get_contents($argv[1]);
     if (strlen($str) == 0) {
         echo 'unknow file : '.$argv;
         exit;
     }

     // extracted code from /typo3/mod/tools/em/class.em_terconnection.php::decodeExchangeData() function
     $parts = explode(':',$str,3);
     if ($parts[1]=='gzcompress')    {
         if (function_exists('gzuncompress'))    {
             $parts[2] = gzuncompress($parts[2]);
         }
         else {
             echo 'Decoding Error: No decompressor available for compressed content. gzcompress()/gzuncompress() functions are not available!';
         }
     }
     if (md5($parts[2]) == $parts[0])    {
         $fetchData = array(unserialize($parts[2]), '');
         if (is_array($fetchData))    {
             // make print_r result file
             if ($f = fopen(basename($argv[1]).".txt", "wb")) {
                 fputs($f, print_r($fetchData[0], true));
                 fclose($f);
             }
             // extract content (create folders and files on disk)

             if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES']))    {
                 $extKey = $fetchData[0]['extKey'];

                 // Create extension directory:
                 $res = array(trim($extKey).'/');
                 $extDirPath = $res[0];
                 mkdir($extDirPath);
                 if (!is_dir($extDirPath)) {
                     echo 'ERROR: Could not create extension directory "'.$extDirPath.'"';
                     exit;
                 }

                 $EM_CONF = $fetchData[0]['EM_CONF'];
                 $emConfFile = construct_ext_emconf_file($extKey, $EM_CONF);
                 $dirs = extractDirsFromFileList(array_keys($fetchData[0]['FILES']));

                 $res = createDirsInPath($dirs,$extDirPath);
                 if (!$res)    {
                     $writeFiles = $fetchData[0]['FILES'];
                     $writeFiles['ext_emconf.php']['content'] = $emConfFile;
                     $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);

                         // Write files:
                     foreach($writeFiles as $theFile => $fileData)    {
                         writeFile($extDirPath.$theFile,$fileData['content']);
                         if (!@is_file($extDirPath.$theFile))    {
                             $content.='Error: File "'.$extDirPath.$theFile.'" could not be created!!!\n';
                         }
                         elseif (md5(file_get_contents($extDirPath.$theFile)) != $fileData['content_md5']) {
                             $content.='Error: File "'.$extDirPath.$theFile.'" MD5 was different from the original files MD5 - so the file is corrupted!\n';
                         }
                     }
                     echo $content;
                 }
                 else {
                     echo $res;
                 }
             }
             else {
                 echo 'Error: No extension key!!! Why? - nobody knows... (Or no files in the file-array...)';
             }
         }
         else {
             echo 'Error: Content could not be unserialized to an array. Strange (since MD5 hashes match!)';
         }
     }
?>

