Skip to content
sept 6 / David Regnier

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.

Prenons comme exemple une tâche qui est responsable chaque nuit de faire un « backup » de la base de données Typo3.

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

Le nom crontab est arbitraire pour le « plugin » qui va rassembler toutes vos tâches, pour plus de clarté il faut implémenter un « helper » que nous appellerons « common »

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']);
}
?>
Si vous avez des problèmes de « timeout » il suffit de rajouter: ini_set(‘memory_limit’, ’512M’);

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

Laisser un commentaire


5 + 7 =