Implémentation d’une tâche via le « Scheduler » Typo3 (backup de la BD Typo3)
Cet article traite de la possibilité d’intégrer des tâches via Typo3 (« plugin » interne « scheduler ») avec un « cron » Linux.
Pour ce faire nous avons besoins des fichiers suivants (deux modules FE):
ext\crontab\ext_autoload.php
ext\crontab\ext_localconf.php
ext\crontab\ext_tables.php
ext\crontab\cron\class.tx_crontab_mysqldump.php
ext\crontab\cron\class.tx_crontab_mysqldump_additionalfieldprovider.php
ext\crontab\locallang.xml
ext\crontab\locallang_csh.xml
ext\common\pi1\class.tx_common_buildtaskconfiguration_lib.php
ext\common\pi1\class.tx_common_pi1.php
ext\common\pi1\class.zip_lib.php
1) Explication des différents fichiers (premier module FE, les tâches)
ext\crontab\ext_autoload.php
Ce fichier est obligatoire, il va charger les classes (vos tâches).
ext\crontab\ext_localconf.php
Configuration des tâches, chemin des fichiers de langue.
ext\crontab\ext_tables.php
Initialise le « context sensitive help – csh », en fait le fichier de langue pour les tâches qui seront affichées depuis le plugin « scheduler ».
ext\crontab\cron\class.tx_crontab_mysqldump.php
La classe responsable de la tâche elle-même.
ext\crontab\cron\class.tx_crontab_mysqldump_additionalfieldprovider.php
La classe pour des éventuels champs additionnels dans chaque tâche.
ext\crontab\locallang.xml
Fichier standard de langue Typo3.
ext\crontab\locallang_csh.xml
Le fichier « context sensitive help » pour le « scheduler ».
2) Explication des différents fichiers (deuxième module FE, le « helper »)
ext\common\pi1\class.tx_common_buildtaskconfiguration_lib.php
Classe responsable de la création des répertoires utiles pour chaque tâche et du fichier de « log ».
ext\common\pi1\class.tx_common_pi1.php
Classe de type « helper », ensemble de fonctions qui vont nous aider à implémenter chaque tâche.
ext\common\pi1\class.zip_lib.php
Classe externe qui va archiver chaque « backup MySQL ».
3) Contenu des différents fichiers
Fichier: ext\crontab\ext_autoload.php
<?php /* * Register necessary class names with autoloader * Used with Scheduler */ return array( 'tx_crontab_mysqldump' => t3lib_extMgm::extPath('crontab', 'cron/class.tx_crontab_mysqldump.php'), 'tx_crontab_mysqldump_additionalfieldprovider' => t3lib_extMgm::extPath('crontab', 'cron/class.tx_crontab_mysqldump_additionalfieldprovider.php') ); ?>
Fichier: ext\crontab\ext_localconf.php
<?php if (!defined ('TYPO3_MODE')) { die ('Access denied.'); } t3lib_extMgm::addPItoST43($_EXTKEY, 'pi1/class.tx_crontab_pi1.php', '_pi1', '', 0); /* * Register information for the tasks * Used with Scheduler */ // MySQL dump process $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['tx_crontab_mysqldump'] = array( 'extension' => $_EXTKEY, 'title' => 'LLL:EXT:' . $_EXTKEY . '/locallang.xml:scheduler_mysqldump_title', 'description' => 'LLL:EXT:' . $_EXTKEY . '/locallang.xml:scheduler_mysqldump_description', 'additionalFields' => 'tx_crontab_mysqldump_additionalfieldprovider' ); ?>
Fichier: ext\crontab\ext_tables.php
<?php if (!defined('TYPO3_MODE')) { die ('Access denied.'); } if (TYPO3_MODE == 'BE') { // Initialize context sensitive help (csh) for the scheduler task t3lib_extMgm::addLLrefForTCAdescr('xMOD_tx_crontab', 'EXT:' . $_EXTKEY . '/locallang_csh.xml'); } ?>
Classe: ext\crontab\cron\class.tx_crontab_mysqldump.php
<?php ini_set('memory_limit', '512M'); require_once(t3lib_extMgm::extPath('common').'pi1/class.tx_common_buildtaskconfiguration_lib.php'); require_once(t3lib_extMgm::extPath('common').'pi1/class.tx_common_pi1.php'); class tx_crontab_mysqldump extends tx_scheduler_Task { private $extKey = 'crontab'; // Ext name private $prefixId = 'scheduler_mysqldump_'; // Prefix name for xml label private $taskObj; // Task config object private $taskArchiveDir; // Path to archive dir private $dumpFileNameSQL; // Dump sql file name private $dumpFileNameZIP; // Full path to zip file name private $extension = array( 'sql' => '.sql', 'zip' => '.zip' ); private $fileNameSQL; private $fileNameZIP; private $taskConfig = array( 'root_dir' => 'crontab_process', 'sub_dir' => 'mysql_dump', 'archive_dir' => 'mysql_dump', 'log_file_name' => 'mysql_dump.log' ); // Args needed for constructor /** * Function executed from the Scheduler * This is the only mandatory method * * @return boolean */ public function execute() { $result = false; // Create task configuration $this->buildTaskStructure(); // Get file name $this->fileNameSQL = $this->dbDumpName.tx_common_pi1::getCurrentDateForArchive('').$this->extension['sql']; $this->fileNameZIP = $this->dbDumpName.tx_common_pi1::getCurrentDateForArchive('').$this->extension['zip']; $this->dumpFileNameSQL = $this->taskArchiveDir.$this->fileNameSQL ; $this->dumpFileNameZIP = $this->taskArchiveDir.$this->fileNameZIP; // DB dump if (tx_common_pi1::sqlSystemDoDumpDBSingleOption($this->dbOptions, $this->dumpFileNameSQL)) { tx_common_pi1::doZipFile($this->dumpFileNameSQL, $this->dumpFileNameZIP); tx_common_pi1::doLogInfo( $this->taskObj->getLogFileName(), $this->prefixId, 'notice_success', tx_common_pi1::getFileSizeFormat($this->dumpFileNameZIP).' '.$this->fileNameZIP ); // Delete old dump files tx_common_pi1::doRemoveFile($this->dumpFileNameSQL); tx_common_pi1::doRemoveOldFiles($this->taskArchiveDir, $this->dbDumpName, $this->nbFilesToKeep); $result = true; } return $result; } /** * Create task configuration * * @return void */ private function buildTaskStructure() { $this->taskObj = tx_common_pi1::createTaskConfigurationObject($this->taskConfig); $this->taskObj->createFilesAndFolderStructure(); $this->taskArchiveDir = $this->taskObj->getArchiveDir().'/'; // Full path to archive dir } /** * This method display which dump name is executed * * @return string */ public function getAdditionalInformation() { return $this->dbDumpName; } } if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/crontab/cron/class.tx_crontab_mysqldump.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/crontab/cron/class.tx_crontab_mysqldump.php']); } ?>
La seule fonction obligatoire est execute() elle doit être implémenté (interface), vous pouvez également implémenter (pas obligatoire) la fonction getAdditionalInformation() qui va ajouter des informations supplémentaires dans l’affichage de la tâche.
Classe: ext\crontab\cron\class.tx_crontab_mysqldump_additionalfieldprovider.php
<?php class tx_crontab_mysqldump_additionalfieldprovider implements tx_scheduler_AdditionalFieldProvider { /** * This method is used to define new fields for adding or editing a task * * The array is multidimensional, keyed to the task class name and each field's id * For each field it provides an associative sub-array with the following: * ['code'] => The HTML code for the field * ['label'] => The label of the field (possibly localized) * ['cshKey'] => The CSH key for the field * ['cshLabel'] => The code of the CSH label * * @param array $taskInfo: reference to the array containing the info used in the add/edit form * @param object $task: when editing, reference to the current task object. Null when adding. * @param tx_scheduler_Module $parentObject: reference to the calling object (Scheduler's BE module) * @return array Array containg all the information pertaining to the additional fields */ public function getAdditionalFields(array &$taskInfo, $task, tx_scheduler_Module $parentObject) { // Initialize extra field value if (empty($taskInfo['dbOptions'])) { if ($parentObject->CMD == 'add') { $taskInfo['dbOptions'] = '--user=typo3 --password=typo3 --databases'; } elseif ($parentObject->CMD == 'edit') { $taskInfo['dbOptions'] = $task->dbOptions; } else { $taskInfo['dbOptions'] = ''; } } if (empty($taskInfo['dbDumpName'])) { if ($parentObject->CMD == 'add') { $taskInfo['dbDumpName'] = 'typo3_'; } elseif ($parentObject->CMD == 'edit') { $taskInfo['dbDumpName'] = $task->dbDumpName; } else { $taskInfo['dbDumpName'] = ''; } } if (empty($taskInfo['nbFilesToKeep'])) { if ($parentObject->CMD == 'add') { $taskInfo['nbFilesToKeep'] = 5; } elseif ($parentObject->CMD == 'edit') { $taskInfo['nbFilesToKeep'] = $task->nbFilesToKeep; } else { $taskInfo['nbFilesToKeep'] = ''; } } $additionalFields = array(); $fieldID = 'task_dbOptions'; $fieldCode = '<input type="text" name="tx_scheduler[dbOptions]" id="'.$fieldID.'" value="'.$taskInfo['dbOptions'].'" size="75" />'; $additionalFields[$fieldID] = array( 'code' => $fieldCode, 'label' => 'LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_dboptions', 'cshKey' => 'xMOD_tx_crontab', 'cshLabel' => $fieldID ); $fieldID = 'task_dbDumpName'; $fieldCode = '<input type="text" name="tx_scheduler[dbDumpName]" id="'.$fieldID.'" value="'.$taskInfo['dbDumpName'].'" size="20" />'; $additionalFields[$fieldID] = array( 'code' => $fieldCode, 'label' => 'LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_dbdumpname', 'cshKey' => 'xMOD_tx_crontab', 'cshLabel' => $fieldID ); $fieldID = 'task_nbFilesToKeep'; $fieldCode = '<input maxlength="1" type="text" name="tx_scheduler[nbFilesToKeep]" id="'.$fieldID.'" value="'.$taskInfo['nbFilesToKeep'].'" size="1" />'; $additionalFields[$fieldID] = array( 'code' => $fieldCode, 'label' => 'LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_nbfilestokeep', 'cshKey' => 'xMOD_tx_crontab', 'cshLabel' => $fieldID ); return $additionalFields; } /** * This method checks any additional data that is relevant to the specific task * If the task class is not relevant, the method is expected to return true * * @param array $submittedData: reference to the array containing the data submitted by the user * @param tx_scheduler_Module $parentObject: reference to the calling object (Scheduler's BE module) * @return boolean True if validation was ok (or selected class is not relevant), false otherwise */ public function validateAdditionalFields(array &$submittedData, tx_scheduler_Module $parentObject) { if (empty($submittedData['dbOptions'])) { $parentObject->addMessage($GLOBALS['LANG']->sL('LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_invalid_dboptions'), t3lib_FlashMessage::ERROR); $result = false; } else { $result = true; } if (!tx_common_pi1::isAlphaNumString($submittedData['dbDumpName'], array('_'))) { $parentObject->addMessage($GLOBALS['LANG']->sL('LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_invalid_dbdumpname'), t3lib_FlashMessage::ERROR); $result = false; } else { $result = true; } if (!tx_common_pi1::isNumeric($submittedData['nbFilesToKeep']) || $submittedData['nbFilesToKeep'] <= 0) { $parentObject->addMessage($GLOBALS['LANG']->sL('LLL:EXT:crontab/locallang.xml:scheduler_mysqldump_additionalfield_invalid_nbfilestokeep'), t3lib_FlashMessage::ERROR); $result = false; } else { $result = true; } return $result; } /** * This method is used to save any additional input into the current task object * if the task class matches * * @param array $submittedData: array containing the data submitted by the user * @param tx_scheduler_Task $task: reference to the current task object * @return void */ public function saveAdditionalFields(array $submittedData, tx_scheduler_Task $task) { $task->dbOptions = $submittedData['dbOptions']; $task->dbDumpName = $submittedData['dbDumpName']; $task->nbFilesToKeep = $submittedData['nbFilesToKeep']; } } if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/crontab/cron/class.tx_crontab_mysqldump_additionalfieldprovider.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/crontab/cron/class.tx_crontab_mysqldump_additionalfieldprovider.php']); } ?>
Fichier: ext\crontab\locallang.xml
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <T3locallang> <meta type="array"> <type>module</type> <description>General language labels for extension 'crontab'</description> </meta> <data type="array"> <languageKey index="default" type="array"> <label index="scheduler_mysqldump_title">[Crontab] MySQL Dump</label> <label index="scheduler_mysqldump_description">This task call class.tx_crontab_mysqldump.php, this task dump database</label> <label index="scheduler_mysqldump_additionalfield_dboptions">DB options, you must give a valid credentials, database name or table, host if needed.</label> <label index="scheduler_mysqldump_additionalfield_dbdumpname">Dump file name (start with)</label> <label index="scheduler_mysqldump_additionalfield_nbfilestokeep">How many files you want to keep for backup</label> <label index="scheduler_mysqldump_additionalfield_invalid_dbdumpname">[scheduler]: [MySQL Dump] You must set a valid dump file name</label> <label index="scheduler_mysqldump_additionalfield_invalid_nbfilestokeep">[scheduler]: [MySQL Dump] You must set a numeric value</label> <label index="scheduler_mysqldump_additionalfield_invalid_dboptions">[scheduler]: [MySQL Dump] You must set a valid credentials</label> <label index="scheduler_mysqldump_notice_success">[scheduler]: [MySQL Dump] MySQL dump is done : size => </label> </languageKey> </data> </T3locallang>
Fichier: ext\crontab\locallang_csh.xml
<?xml version="1.0" encoding="utf-8" standalone="yes" ?> <T3locallang> <meta type="array"> <description>Contents of scheduler task csh</description> <type>CSH</type> <csh_table>xMOD_tx_crontab</csh_table> <fileId>EXT:crontab/locallang_csh.xml</fileId> <labelContext type="array"> </labelContext> </meta> <data type="array"> <languageKey index="default" type="array"> <label index="task_dbOptions.alttitle">MySQL dump options</label> <label index="task_dbOptions.description">Set MySQL dump options, you must give a valid credentials, database name or table, host if needed, sample: --user=typo3 --password=typo3 --skip-opt --add-drop-table --create-options --disable-keys --extended-insert --quick --default-character-set=latin1 --skip-lock-tables --host=127.0.0.1 --databases mydatabasename</label> <label index="task_dbDumpName.alttitle">MySQL dump file name</label> <label index="task_dbDumpName.description">Set MySQL dump file name, sample: typo3_, the application will concatenate date and extension itself, the result will be typo3_20101008.zip</label> </languageKey> </data> </T3locallang>
Classe : ext\common\pi1\class.tx_common_buildtaskconfiguration_lib.php
<?php final class tx_common_buildtaskconfiguration_lib { // Starting point for root dir private $pathToRootDir = 'fileadmin/user_upload/'; // Constructor args private $argsArray = array( 'root_dir' => '', 'sub_dir' => '', 'archive_dir' => '', 'config_dir' => '', 'misc_dir' => '', 'log_file_name' => '' ); /** * Create object constructor * * @param array $structure: array of args used by constructor * @return void */ public function __construct(array $structure) { $this->argsArray['root_dir'] = $structure['root_dir']; $this->argsArray['sub_dir'] = $structure['sub_dir']; $this->argsArray['archive_dir'] = $structure['archive_dir']; $this->argsArray['config_dir'] = $structure['config_dir']; $this->argsArray['misc_dir'] = $structure['misc_dir']; $this->argsArray['log_file_name'] = $structure['log_file_name']; } /** * Create structure for common task * * @return void */ public function createFilesAndFolderStructure() { tx_common_pi1::createFolder($this->setRootDir()); tx_common_pi1::createFolder($this->setRootSubDir()); tx_common_pi1::createFolder($this->setArchiveDir()); tx_common_pi1::createFolder($this->setConfigDir()); tx_common_pi1::createMultiFolder($this->setMiscDir()); tx_common_pi1::createFile($this->setLogFileName()); } /** * Set root dir path, starting point after $this->pathToRootDir * * @return mixed */ private function setRootDir() { return (!empty($this->argsArray['root_dir'])) ? $this->argsArray['root_dir'] = PATH_site.$this->pathToRootDir.$this->argsArray['root_dir'] : null; } /** * Add dir inside $this->pathToRootDir if needed * * @return mixed */ private function setRootSubDir() { return (!empty($this->argsArray['sub_dir'])) ? $this->argsArray['sub_dir'] = $this->argsArray['root_dir'].'/'.$this->argsArray['sub_dir'] : null; } /** * Set archive dir path * * @return mixed */ private function setArchiveDir() { return (!empty($this->argsArray['archive_dir'])) ? $this->argsArray['archive_dir'] = $this->setRootPath().'/'.$this->argsArray['archive_dir'] : null; } /** * Set config dir path * * @return mixed */ private function setConfigDir() { return (!empty($this->argsArray['config_dir'])) ? $this->argsArray['config_dir'] = $this->setRootPath().'/'.$this->argsArray['config_dir'] : null; } /** * Set extra dir if we need * * @return array */ private function setMiscDir() { if (!empty($this->argsArray['misc_dir'])) { foreach ($this->argsArray['misc_dir'] as $key => $val) { $miscDirArray[$key] = $this->setRootPath().'/'.$val; } } return $this->argsArray['misc_dir'] = $miscDirArray; } /** * Set log file name * * @return mixed */ private function setLogFileName() { return (!empty($this->argsArray['log_file_name'])) ? $this->argsArray['log_file_name'] = $this->setRootPath().'/'.$this->argsArray['log_file_name'] : null; } /** * Adjust root if sub exist * * @return string */ private function setRootPath() { return (empty($this->argsArray['sub_dir'])) ? $this->argsArray['root_dir'] : $this->argsArray['sub_dir']; } /** * Get archive dir * * @return mixed */ public function getArchiveDir() { return (!empty($this->argsArray['archive_dir'])) ? $this->argsArray['archive_dir'] : null; } /** * Get config dir * * @return mixed */ public function getConfigDir() { return (!empty($this->argsArray['config_dir'])) ? $this->argsArray['config_dir'] : null; } /** * Get misc dir * * @param string $key: valid key to retrieve * @return mixed */ public function getMiscDir($key = '') { return (!empty($this->argsArray['misc_dir'])) ? $this->argsArray['misc_dir'][$key] : null; } /** * Get log file name * * @return mixed */ public function getLogFileName() { return (!empty($this->argsArray['log_file_name'])) ? $this->argsArray['log_file_name'] : null; } } if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/common/pi1/class.tx_common_buildtaskconfiguration_lib.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/common/pi1/class.tx_common_buildtaskconfiguration_lib.php']); } ?>
Classe : ext\common\pi1\class.tx_common_pi1.php
<?php require_once(PATH_tslib.'class.tslib_pibase.php'); require_once(t3lib_extMgm::extPath('common').'pi1/class.zip_lib.php'); class tx_common_pi1 extends tslib_pibase { // Same as class name public $prefixId = 'tx_common_pi1'; // Path to this script relative to the extension dir. public $scriptRelPath = 'pi1/class.tx_common_pi1.php'; // The extension key. public $extKey = 'common'; /** * Return date * * @param string $separator: If we need a separator * @return string */ public static function getCurrentDateForArchive($separator = '_') { return date('Ymd').$separator; } /** * Do MySQLDump for DB (single mode) * * @param string $options: table name * @param string $outputSQLFile: file name result * @return boolean */ public static function sqlSystemDoDumpDBSingleOption($options, $outputSQLFile) { $result = false; if (self::isFunctionEnabled('system')) { system("mysqldump ".$options." > ".$outputSQLFile.""); if (self::isFileExistAndNotEmpty($outputSQLFile)) { $result = true; } } return $result; } /** * See if function is enabled on server * * @param string $functionToCheck: name of the function PHP * @return boolean */ public static function isFunctionEnabled($functionToCheck) { $result = false; $disabled = explode(',', ini_get('disable_functions')); if (function_exists($functionToCheck) && !in_array($functionToCheck, $disabled)) { $result = true; } return $result; } /** * See if input file exist and not empty * * @param string $inputString: file * @return boolean */ public static function isFileExistAndNotEmpty($inputString) { $result = false; if (!empty($inputString) && is_file($inputString) && filesize($inputString) > 0) { $result = true; } return $result; } /** * Zip file * * @param string $fileNameToZip: file name to zip * @param string $outputZipFileName: name of the output zip file * @return boolean */ public static function doZipFile($fileNameToZip = '', $outputZipFileName = '') { $result = false; $zipObject = t3lib_div::makeInstance('zipfile'); $fileSize = filesize($fileNameToZip); if ($fileSize > 0) { if ($handle = fopen($fileNameToZip, 'rb', false)) { $data = fread($handle, $fileSize); if (is_object($zipObject)) { $zipObject->addFile($data, basename($fileNameToZip)); // Just the file name, remove the full path $fileZipped = $zipObject->file(); if ($fileHandle = fopen($outputZipFileName, "w")) { fwrite($fileHandle, $fileZipped); fclose($fileHandle); $result = true; } } } } return $result; } /** * Write to log file, abstract layer for => writeToLogFile * * @param string $logFileName: path to log file mane * @param string $prefixNameForLabel: prefix for label * @param string $label: label name from xml file * @param string $extraContent: extra content if needed * @param string $extKey: ext key name * @return void */ public static function doLogInfo($logFileName = '', $prefixNameForLabel, $label, $extraContent = '', $extKey = 'crontab') { self::writeToLogFile( $logFileName, self::getLabel( $extKey, $prefixNameForLabel, $label ), $extraContent, true ); } /** * Write to log file * * @param string $file: file path * @param string $extraContent: extra content to write * @param string $content: the content to write * @param boolean $dateTime: date and time * @param string $separator: separator * @return boolean */ public static function writeToLogFile($file, $content, $extraContent, $dateTime = false, $separator = " => ") { $result = false; $date = ""; $endLine = "\n"; // Set date if needed if ($dateTime) { $date = self::getCurrentDateTime().$separator; } if ($fileHandle = fopen($file, 'a')) { fwrite($fileHandle, $date.$content.$extraContent.$endLine); fclose($fileHandle); t3lib_div::fixPermissions($file); // Change permissions related to Typo3 $result = true; } return $result; } /** * Return datetime * * @return string */ public static function getCurrentDateTime() { return date('Y-m-d H:i:s'); } /** * Get label from xml file * * @param string $key: ext key * @param string $prefix: prefix name * @param string $label: label from xml file * @return string */ public static function getLabel($key, $prefix, $label) { return $GLOBALS['LANG']->sL('LLL:EXT:'.$key.'/locallang.xml:'.$prefix.$label); } /** * Format file size * * @param string $inputFile: file * @return mixed */ public static function getFileSizeFormat($inputFile = '') { $result = false; if (self::isFileExistAndNotEmpty($inputFile)) { $fileSize = filesize($inputFile); $result = (round($fileSize/pow(1024, ($i = floor(log($fileSize, 1024)))), $i > 1 ? 2 : 0)); } return $result; } /** * Delete file * * @param string $inputFile: source file * @return boolean */ public static function doRemoveFile($inputFile = '') { $result = false; if (!empty($inputFile) && self::isFileExistAndNotEmpty($inputFile)) { if (unlink($inputFile)) { $result = true; } } return $result; } /** * Delete files from dir with pattern * * @param string $rootDir: root dir * @param string $wordPattern: word pattern to match file name * @param int $nbFilesToKeep: default 2 files to keep from dir * @return boolean */ public static function doRemoveOldFiles($rootDir = '', $wordPattern = '', $nbFilesToKeep = 2) { $result = false; if (!empty($rootDir) && !empty($wordPattern)) { $filesArray = self::getFileFromDir($rootDir); foreach ($filesArray as $item) { preg_match("#(".$wordPattern."+?)#s", $item, $file); if (!empty($file[1])) { $files[] = $item; } } if (!is_null($files)) { rsort($files); $i = 1; foreach ($files as $key => $value) { if ($i > $nbFilesToKeep) { self::doRemoveFile($rootDir.$value); } $i++; } } } return $result; } /** * Get file(s) from given dir, * add optional valid only extension * Call sample => tx_common_pi1::getFileFromDir($rootDir, 'log') will get only log file(s) from dir * * @param string $rootDir: path to root dir * @param string $onlyValidExtension: valid extension name * @return array */ public static function getFileFromDir($rootDir, $onlyValidExtension = '') { $files = array(); // Open dir if ($dir = opendir($rootDir)) { // Loop through dir while(($myFile = readdir($dir)) !== false) { // Filter, get only files from dir if ($myFile != '.' && $myFile != '..' && self::isFileExistAndNotEmpty($rootDir.$myFile)) { $files[] = $myFile; } } // Close dir closedir($dir); // Filter only given extension if (!empty($onlyValidExtension)) { foreach ($files as $key => $value) { // Unset other extension if (!self::isValidExtension($rootDir.$value, $onlyValidExtension)) { unset($files[$key]); } } } } return $files; } /** * Check if the given input contain the extension name * Call sample => tx_common_pi1::isValidExtension($this->pathToFile, 'csv') * * @param string $inputString: input string to check * @param string $extensionName: extension name * @return boolean */ public static function isValidExtension($inputString, $extensionName) { $result = false; $filteredString = trim($inputString); // Check if we have input if (!empty($filteredString) && !empty($extensionName)) { // Use regex if (preg_match('/.'.$extensionName.'/i', $filteredString)=='1') { $result = true; } } return $result; } /** * Create task configuration * * @param array $structure: structure for constructor * @return mixed */ public static function createTaskConfigurationObject(array $structure) { $result = ''; if (!empty($structure)) { $taskObj = t3lib_div::makeInstance( 'tx_common_buildtaskconfiguration_lib', $structure ); if (is_object($taskObj)) { $result = $taskObj; } } return $result; } /** * Check if the given string is alphanumeric, * add optional valid string, must be an array: array('.', '_', '-') * * @param string $inputString: input string to check * @param array $arrayOfValidString: array of valid string to keep * @return boolean */ public static function isAlphaNumString($inputString, $arrayOfValidString = array()) { $result = false; $filteredString = trim($inputString); // Check if we have input if (!empty($filteredString)) { // If we have valid string to remove if (!empty($arrayOfValidString)) { $filteredString = str_replace($arrayOfValidString, '', $filteredString); } // Test string, should be alphanum if (ctype_alnum($filteredString)) { $result = true; } } return $result; } /** * Check if the given input is numeric, * add optional valid string, must be an array: array('.') => this check an IP * * @param string $inputString: input string to check * @param array $arrayOfValidString: array of valid string to keep * @return boolean */ public static function isNumeric($inputString, $arrayOfValidString = array()) { $result = false; $filteredString = trim($inputString); // Check if we have input if (!empty($filteredString)) { // If we have valid string to remove if (!empty($arrayOfValidString)) { $filteredString = str_replace($arrayOfValidString, '', $filteredString); } // Test string, should be numeric if (ctype_digit($filteredString)) { $result = true; } } return $result; } } if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/common/pi1/class.tx_common_pi1.php']) { include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/common/pi1/class.tx_common_pi1.php']); } ?>
Classe : ext\common\pi1\class.zip_lib.php
<?php /* $Id: zip.lib.php,v 2.4 2004/11/03 13:56:52 garvinhicking Exp $ */ // vim: expandtab sw=4 ts=4 sts=4: /** * Zip file creation class. * Makes zip files. * * Based on : * * http://www.zend.com/codex.php?id=535&single=1 * By Eric Mueller <eric@themepark.com> * * http://www.zend.com/codex.php?id=470&single=1 * by Denis125 <webmaster@atlant.ru> * * a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified * date and time of the compressed file * * Official ZIP file format: http://www.pkware.com/appnote.txt * * @access public */ class zipfile { /** * Array to store compressed data * * @var array $datasec */ var $datasec = array(); /** * Central directory * * @var array $ctrl_dir */ var $ctrl_dir = array(); /** * End of central directory record * * @var string $eof_ctrl_dir */ var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; /** * Last offset position * * @var integer $old_offset */ var $old_offset = 0; /** * Converts an Unix timestamp to a four byte DOS date and time format (date * in high two bytes, time in low two bytes allowing magnitude comparison). * * @param integer the current Unix timestamp * * @return integer the current date in a four byte DOS format * * @access private */ function unix2DosTime($unixtime = 0) { $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime); if ($timearray['year'] < 1980) { $timearray['year'] = 1980; $timearray['mon'] = 1; $timearray['mday'] = 1; $timearray['hours'] = 0; $timearray['minutes'] = 0; $timearray['seconds'] = 0; } // end if return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); } // end of the 'unix2DosTime()' method /** * Adds "file" to archive * * @param string file contents * @param string name of the file in the archive (may contains the path) * @param integer the current timestamp * * @access public */ function addFile($data, $name, $time = 0) { $name = str_replace('\\', '/', $name); $dtime = dechex($this->unix2DosTime($time)); $hexdtime = '\x' . $dtime[6] . $dtime[7] . '\x' . $dtime[4] . $dtime[5] . '\x' . $dtime[2] . $dtime[3] . '\x' . $dtime[0] . $dtime[1]; eval('$hexdtime = "' . $hexdtime . '";'); $fr = "\x50\x4b\x03\x04"; $fr .= "\x14\x00"; // ver needed to extract $fr .= "\x00\x00"; // gen purpose bit flag $fr .= "\x08\x00"; // compression method $fr .= $hexdtime; // last mod time and date // "local file header" segment $unc_len = strlen($data); $crc = crc32($data); $zdata = gzcompress($data); $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug $c_len = strlen($zdata); $fr .= pack('V', $crc); // crc32 $fr .= pack('V', $c_len); // compressed filesize $fr .= pack('V', $unc_len); // uncompressed filesize $fr .= pack('v', strlen($name)); // length of filename $fr .= pack('v', 0); // extra field length $fr .= $name; // "file data" segment $fr .= $zdata; // "data descriptor" segment (optional but necessary if archive is not // served as file) // nijel(2004-10-19): this seems not to be needed at all and causes // problems in some cases (bug #1037737) //$fr .= pack('V', $crc); // crc32 //$fr .= pack('V', $c_len); // compressed filesize //$fr .= pack('V', $unc_len); // uncompressed filesize // add this entry to array $this -> datasec[] = $fr; // now add to central directory record $cdrec = "\x50\x4b\x01\x02"; $cdrec .= "\x00\x00"; // version made by $cdrec .= "\x14\x00"; // version needed to extract $cdrec .= "\x00\x00"; // gen purpose bit flag $cdrec .= "\x08\x00"; // compression method $cdrec .= $hexdtime; // last mod time & date $cdrec .= pack('V', $crc); // crc32 $cdrec .= pack('V', $c_len); // compressed filesize $cdrec .= pack('V', $unc_len); // uncompressed filesize $cdrec .= pack('v', strlen($name) ); // length of filename $cdrec .= pack('v', 0 ); // extra field length $cdrec .= pack('v', 0 ); // file comment length $cdrec .= pack('v', 0 ); // disk number start $cdrec .= pack('v', 0 ); // internal file attributes $cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header $this -> old_offset += strlen($fr); $cdrec .= $name; // optional extra field, file comment goes here // save to central directory $this -> ctrl_dir[] = $cdrec; } // end of the 'addFile()' method /** * Dumps out file * * @return string the zipped file * * @access public */ function file() { $data = implode('', $this -> datasec); $ctrldir = implode('', $this -> ctrl_dir); return $data . $ctrldir . $this -> eof_ctrl_dir . pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk" pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall pack('V', strlen($ctrldir)) . // size of central dir pack('V', strlen($data)) . // offset to start of central dir "\x00\x00"; // .zip file comment length } // end of the 'file()' method } // end of the 'zipfile' class ?>
4) Configuration du cron sous Linux
Il suffit simplement d’ajouter une ligne dans le cron, en mode édition:
crontab -e
# Call the scheduler
* * * * * /usr/bin/php /www/html/votre_instance_typo3/typo3/cli_dispatch.phpsh scheduler >/dev/null 2>&1
Cette configuration du « cron » est arbitraire (le fichier est appelé toutes les minutes, tous les jours, voir les possibilités dans la documentation officielle crontab), vous devez faire votre propre configuration pour les chemins.
Pour vous aider dans la création d’une tâche, voici la documentation officielle : manuel scheduler Typo3