Fix: regression, replace triggers by hooks

This commit is contained in:
Regis Houssin 2012-09-12 12:27:11 +02:00
parent 8fd384373a
commit b75efdcf10
2 changed files with 163 additions and 270 deletions

View File

@ -565,196 +565,136 @@ function dol_unescapefile($filename)
* @param int $allowoverwrite 1=Overwrite target file if it already exists * @param int $allowoverwrite 1=Overwrite target file if it already exists
* @param int $disablevirusscan 1=Disable virus scan * @param int $disablevirusscan 1=Disable virus scan
* @param string $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error']) * @param string $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error'])
* @param int $notrigger Disable all triggers * @param int $nohook Disable all hooks
* @param string $varfiles _FILES var name * @param string $varfiles _FILES var name
* @return int >0 if OK, <0 or string if KO * @return int >0 if OK, <0 or string if KO
* @see dolCheckUploadedFile, dol_move * @see dolCheckUploadedFile, dol_move
*/ */
function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $notrigger=0, $varfiles='addedfile') function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile')
{ {
global $db, $hookmanager; global $conf, $db, $user, $langs;
global $object; global $object, $hookmanager;
$error=0; $error=0;
// Check uploaded file
$dest_file=dolCheckUploadedFile($src_file, $dest_file, $disablevirusscan, $uploaderrorcode);
if (is_array($dest_file) && isset($dest_file['error'])) return $dest_file['error'];
if (! is_object($hookmanager))
{
if (! class_exists('HookManager')) {
// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
require DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
$hookmanager=new HookManager($db);
}
}
$hookmanager->initHooks(array('fileslib'));
$parameters=array('dest_file' => $dest_file, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite, 'notrigger' => $notrigger);
$reshook=$hookmanager->executeHooks('dolMoveUploadedFile', $parameters, $object);
if (empty($reshook)) {
return dolMoveUploadedFile($src_file, $dest_file, $allowoverwrite, $notrigger);
}
}
/**
* Check an uploaded file.
* If there is errors (virus found, antivir in error, bad filename), file is not moved.
*
* @param string $src_file Source full path filename ($_FILES['field']['tmp_name'])
* @param string $dest_file Target full path filename ($_FILES['field']['name'])
* @param int $disablevirusscan 1=Disable virus scan
* @param string $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error'])
* @return int >0 if OK, <0 or string if KO
* @see dol_move_uploaded_file
*/
function dolCheckUploadedFile($src_file, $dest_file, $disablevirusscan=0, $uploaderrorcode=0)
{
global $conf;
$file_name = $dest_file; $file_name = $dest_file;
// If an upload error has been reported
if ($uploaderrorcode)
{
switch($uploaderrorcode)
{
case UPLOAD_ERR_INI_SIZE: // 1
return array('error' => 'ErrorFileSizeTooLarge');
break;
case UPLOAD_ERR_FORM_SIZE: // 2
return array('error' => 'ErrorFileSizeTooLarge');
break;
case UPLOAD_ERR_PARTIAL: // 3
return array('error' => 'ErrorPartialFile');
break;
case UPLOAD_ERR_NO_TMP_DIR: //
return array('error' => 'ErrorNoTmpDir');
break;
case UPLOAD_ERR_CANT_WRITE:
return array('error' => 'ErrorFailedToWriteInDir');
break;
case UPLOAD_ERR_EXTENSION:
return array('error' => 'ErrorUploadBlockedByAddon');
break;
default:
break;
}
}
// If we need to make a virus scan if (empty($nohook))
if (empty($disablevirusscan) && file_exists($src_file) && ! empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) {
{ // If an upload error has been reported
if (! class_exists('AntiVir')) { if ($uploaderrorcode)
require DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php'; {
} switch($uploaderrorcode)
$antivir=new AntiVir($db); {
$result = $antivir->dol_avscan_file($src_file); case UPLOAD_ERR_INI_SIZE: // 1
if ($result < 0) // If virus or error, we stop here return 'ErrorFileSizeTooLarge';
{ break;
$reterrors=$antivir->errors; case UPLOAD_ERR_FORM_SIZE: // 2
dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$file_name.'") KO with antivirus: result='.$result.' errors='.join(',',$antivir->errors), LOG_WARNING); return 'ErrorFileSizeTooLarge';
return array('error' => 'ErrorFileIsInfectedWithAVirus: '.join(',',$reterrors)); break;
} case UPLOAD_ERR_PARTIAL: // 3
} return 'ErrorPartialFile';
break;
// Security: case UPLOAD_ERR_NO_TMP_DIR: //
// Disallow file with some extensions. We renamed them. return 'ErrorNoTmpDir';
// Car si on a mis le rep documents dans un rep de la racine web (pas bien), cela permet d'executer du code a la demande. break;
if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$file_name)) case UPLOAD_ERR_CANT_WRITE:
{ return 'ErrorFailedToWriteInDir';
$file_name.= '.noexe'; break;
} case UPLOAD_ERR_EXTENSION:
return 'ErrorUploadBlockedByAddon';
// Security: break;
// On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers. default:
if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file)) break;
{ }
dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING); }
return array('error' => -1);
} // If we need to make a virus scan
if (empty($disablevirusscan) && file_exists($src_file) && ! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
// Security: {
// On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans if (! class_exists('AntiVir')) {
// les noms de fichiers. require DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php';
if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file)) }
{ $antivir=new AntiVir($db);
dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING); $result = $antivir->dol_avscan_file($src_file);
return array('error' => -2); if ($result < 0) // If virus or error, we stop here
} {
$reterrors=$antivir->errors;
return $file_name; dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: result='.$result.' errors='.join(',',$antivir->errors), LOG_WARNING);
} return 'ErrorFileIsInfectedWithAVirus: '.join(',',$reterrors);
}
/** }
* Move an uploaded file after some controls.
* If there is errors (virus found, antivir in error, bad filename), file is not moved. // Security:
* // Disallow file with some extensions. We renamed them.
* @param string $src_file Source full path filename ($_FILES['field']['tmp_name']) // Car si on a mis le rep documents dans un rep de la racine web (pas bien), cela permet d'executer du code a la demande.
* @param string $dest_file Target full path filename ($_FILES['field']['name']) if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$dest_file))
* @param int $allowoverwrite 1=Overwrite target file if it already exists {
* @param int $notrigger Disable all triggers $file_name.= '.noexe';
* @return int >0 if OK, <0 or string if KO }
*/
function dolMoveUploadedFile($src_file, $dest_file, $allowoverwrite, $notrigger=0) // Security:
{ // On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers.
global $conf, $user, $langs, $db; if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
global $object; {
dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
$error=0; return -1;
}
// The file functions must be in OS filesystem encoding.
$src_file_osencoded=dol_osencode($src_file); // Security:
$file_name_osencoded=dol_osencode($dest_file); // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans
// les noms de fichiers.
// Check if destination dir is writable if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file))
// TODO {
dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
// Check if destination file already exists return -2;
if (! $allowoverwrite)
{
if (file_exists($file_name_osencoded))
{
dol_syslog("Files.lib::dol_move_uploaded_file File ".$dest_file." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
return 'ErrorFileAlreadyExists';
}
}
// Move file
$return=move_uploaded_file($src_file_osencoded, $file_name_osencoded);
if ($return)
{
if (! empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK));
dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$dest_file." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
if (! $notrigger)
{
if (is_object($object))
{
$object->src_file=$dest_file;
// Appel des triggers
include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
$interface=new Interfaces($db);
$result=$interface->run_triggers('FILE_UPLOAD',$object,$user,$langs,$conf);
if ($result < 0) {
$error++; $errors=$interface->errors;
}
// Fin appel triggers
}
else
{
dol_syslog("Files.lib::dol_move_uploaded_file Object not find", LOG_WARNING);
}
} }
return 1; // Success if (! is_object($hookmanager))
{
if (! class_exists('HookManager')) {
// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
require DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
$hookmanager=new HookManager($db);
}
}
$hookmanager->initHooks(array('fileslib'));
$parameters=array('filename' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
$reshook=$hookmanager->executeHooks('dolMoveUploadedFile', $parameters, $object);
} }
else
if (empty($reshook))
{ {
dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR); // The file functions must be in OS filesystem encoding.
return -3; // Unknown error $src_file_osencoded=dol_osencode($src_file);
$file_name_osencoded=dol_osencode($file_name);
// Check if destination dir is writable
// TODO
// Check if destination file already exists
if (! $allowoverwrite)
{
if (file_exists($file_name_osencoded))
{
dol_syslog("Files.lib::dol_move_uploaded_file File ".$file_name." already exists. Return 'ErrorFileAlreadyExists'", LOG_WARNING);
return 'ErrorFileAlreadyExists';
}
}
// Move file
$return=move_uploaded_file($src_file_osencoded, $file_name_osencoded);
if ($return)
{
if (! empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK));
dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);
return 1; // Success
}
else
{
dol_syslog("Files.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
return -3; // Unknown error
}
} }
} }
@ -764,110 +704,73 @@ function dolMoveUploadedFile($src_file, $dest_file, $allowoverwrite, $notrigger=
* @param string $file File to delete or mask of file to delete * @param string $file File to delete or mask of file to delete
* @param int $disableglob Disable usage of glob like * * @param int $disableglob Disable usage of glob like *
* @param int $nophperrors Disable all PHP output errors * @param int $nophperrors Disable all PHP output errors
* @param int $notrigger Disable all triggers * @param int $nohook Disable all hooks
* @param object $object Current object in use * @param object $object Current object in use
* @return boolean True if file is deleted, False if error * @return boolean True if file is deleted, False if error
*/ */
function dol_delete_file($file,$disableglob=0,$nophperrors=0,$notrigger=0,$object=null) function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=null)
{ {
global $db, $hookmanager; global $db, $conf, $user, $langs;
global $hookmanager;
if (! is_object($hookmanager)) $langs->load("other");
$langs->load("errors");
if (empty($nohook))
{ {
if (! class_exists('HookManager')) { if (! is_object($hookmanager))
// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array {
require DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; if (! class_exists('HookManager')) {
$hookmanager=new HookManager($db); // Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
} require DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
$hookmanager=new HookManager($db);
}
}
$hookmanager->initHooks(array('fileslib'));
$parameters=array(
'file' => $file,
'disableglob'=> $disableglob,
'nophperrors' => $nophperrors
);
$reshook=$hookmanager->executeHooks('deleteFile', $parameters, $object);
} }
$hookmanager->initHooks(array('fileslib'));
$parameters=array( if (empty($nohook) && isset($reshook) && $reshook != '') // 0:not deleted, 1:deleted, null or '' for bypass
'file' => $file,
'disableglob'=> $disableglob,
'nophperrors' => $nophperrors,
'notrigger' => $notrigger
);
$reshook=$hookmanager->executeHooks('deleteFile', $parameters, $object);
if (isset($reshook) && $reshook != '') // 0:not deleted, 1:deleted, null or '' for bypass
{ {
return $reshook; return $reshook;
} }
else else
{ {
return _dolDeleteFile($file, $disableglob, $nophperrors, $notrigger, $object); $error=0;
}
}
/**
* Remove a file or several files with a mask.
* Never call this function ! Call dol_delete_file file instead.
*
* @param string $file File to delete or mask of file to delete
* @param int $disableglob Disable usage of glob like *
* @param int $nophperrors Disable all PHP output errors
* @param int $notrigger Disable all triggers
* @param object $object Current object in use
* @return boolean True if file is deleted, False if error
* @see dol_delete_file
*/
function _dolDeleteFile($file,$disableglob=0,$nophperrors=0,$notrigger=0,$object=null)
{
global $db, $conf, $user, $langs;
$langs->load("other");
$langs->load("errors");
$error=0;
//print "x".$file." ".$disableglob; //print "x".$file." ".$disableglob;
$ok=true; $ok=true;
$file_osencoded=dol_osencode($file); // New filename encoded in OS filesystem encoding charset $file_osencoded=dol_osencode($file); // New filename encoded in OS filesystem encoding charset
if (empty($disableglob) && ! empty($file_osencoded)) if (empty($disableglob) && ! empty($file_osencoded))
{
foreach (glob($file_osencoded) as $filename)
{ {
if ($nophperrors) $ok=@unlink($filename); // The unlink encapsulated by dolibarr foreach (glob($file_osencoded) as $filename)
else $ok=unlink($filename); // The unlink encapsulated by dolibarr
if ($ok)
{ {
dol_syslog("Removed file ".$filename, LOG_DEBUG); if ($nophperrors) $ok=@unlink($filename); // The unlink encapsulated by dolibarr
if (! $notrigger) else $ok=unlink($filename); // The unlink encapsulated by dolibarr
{ if ($ok) dol_syslog("Removed file ".$filename, LOG_DEBUG);
if (! is_object($object)) $object=(object) 'dummy'; else dol_syslog("Failed to remove file ".$filename, LOG_WARNING);
$object->src_file=$file; }
}
// TODO Replace trigger by a hook. Triggers must be used for business events only. else
// REGIS just after of hook testing {
// Appel des triggers if ($nophperrors) $ok=@unlink($file_osencoded); // The unlink encapsulated by dolibarr
include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; else $ok=unlink($file_osencoded); // The unlink encapsulated by dolibarr
$interface=new Interfaces($db); if ($ok) {
$result=$interface->run_triggers('FILE_DELETE',$object,$user,$langs,$conf); dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
if ($result < 0) {
$error++; $errors=$interface->errors;
}
// Fin appel triggers
}
} }
else { else {
dol_syslog("Failed to remove file ".$filename, LOG_WARNING); dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
} }
} }
}
else
{
if ($nophperrors) $ok=@unlink($file_osencoded); // The unlink encapsulated by dolibarr
else $ok=unlink($file_osencoded); // The unlink encapsulated by dolibarr
if ($ok) {
dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG);
}
else {
dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING);
}
}
return $ok; return $ok;
}
} }
/** /**

View File

@ -529,16 +529,6 @@ class InterfaceDemo
dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
} }
elseif ($action == 'SHIPPING_BUILDDOC') elseif ($action == 'SHIPPING_BUILDDOC')
{
dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
}
// File
elseif ($action == 'FILE_UPLOAD')
{
dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
}
elseif ($action == 'FILE_DELETE')
{ {
dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
} }