/**
 *	Make control on an uploaded file from an GUI page and move it to final destination.
 * 	If there is errors (virus found, antivir in error, bad filename), file is not moved.
 *  Note: This function can be used only into a HTML page context. Use dol_move if you are outside.
 *
 *	@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		$allowoverwrite		1=Overwrite target file if it already exists
 * 	@param	int		$disablevirusscan	1=Disable virus scan
 * 	@param	integer	$uploaderrorcode	Value of PHP upload error code ($_FILES['field']['error'])
 * 	@param	int		$nohook				Disable all hooks
 * 	@param	string	$varfiles			_FILES var name
 *	@return int       			  		>0 if OK, <0 or string if KO
 *  @see    dol_move
 */
function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile')
{
    global $conf, $db, $user, $langs;
    global $object, $hookmanager;
    $reshook = 0;
    $file_name = $dest_file;
    if (empty($nohook)) {
        // If an upload error has been reported
        if ($uploaderrorcode) {
            switch ($uploaderrorcode) {
                case UPLOAD_ERR_INI_SIZE:
                    // 1
                    return 'ErrorFileSizeTooLarge';
                    break;
                case UPLOAD_ERR_FORM_SIZE:
                    // 2
                    return 'ErrorFileSizeTooLarge';
                    break;
                case UPLOAD_ERR_PARTIAL:
                    // 3
                    return 'ErrorPartialFile';
                    break;
                case UPLOAD_ERR_NO_TMP_DIR:
                    //
                    return 'ErrorNoTmpDir';
                    break;
                case UPLOAD_ERR_CANT_WRITE:
                    return 'ErrorFailedToWriteInDir';
                    break;
                case UPLOAD_ERR_EXTENSION:
                    return 'ErrorUploadBlockedByAddon';
                    break;
                default:
                    break;
            }
        }
        // If we need to make a virus scan
        if (empty($disablevirusscan) && file_exists($src_file) && !empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) {
            if (!class_exists('AntiVir')) {
                require DOL_DOCUMENT_ROOT . '/core/class/antivir.class.php';
            }
            $antivir = new AntiVir($db);
            $result = $antivir->dol_avscan_file($src_file);
            if ($result < 0) {
                $reterrors = $antivir->errors;
                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);
            }
        }
        // Security:
        // Disallow file with some extensions. We renamed them.
        // 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.
        if (preg_match('/\\.htm|\\.html|\\.php|\\.pl|\\.cgi$/i', $dest_file)) {
            $file_name .= '.noexe';
        }
        // Security:
        // On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers.
        if (preg_match('/^\\./', $src_file) || preg_match('/\\.\\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
            dol_syslog("Refused to deliver file " . $src_file, LOG_WARNING);
            return -1;
        }
        // Security:
        // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans les noms de fichiers.
        if (preg_match('/^\\./', $dest_file) || preg_match('/\\.\\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
            dol_syslog("Refused to deliver file " . $dest_file, LOG_WARNING);
            return -2;
        }
        $reshook = $hookmanager->initHooks(array('fileslib'));
        $parameters = array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite);
        $reshook = $hookmanager->executeHooks('moveUploadedFile', $parameters, $object);
    }
    if ($reshook < 0) {
        $errmsg = join(',', $hookmanager->errors);
        if (empty($errmsg)) {
            $errmsg = 'ErrorReturnedBySomeHooks';
        }
        // Should not occurs. Added if hook is bugged and does not set ->errors when there is error.
        return $errmsg;
    } elseif (empty($reshook)) {
        // The file functions must be in OS filesystem encoding.
        $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
        }
    }
    return 1;
    // Success
}
Exemple #2
0
/**
 *	Move an uploaded file after some controls.
 * 	If there is errors (virus found, antivir in error, bad filename), file is not moved.
 *	@param	src_file			Source full path filename ($_FILES['field']['tmp_name'])
 *	@param	dest_file			Target full path filename
 * 	@param	allowoverwrite		1=Overwrite target file if it already exists
 * 	@param	disablevirusscan	1=Disable virus scan
 * 	@param	uploaderrorcode		Value of upload error code ($_FILES['field']['error'])
 * 	@param	notrigger			Disable all triggers
 *	@return int         		>0 if OK, <0 or string if KO
 */
function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $notrigger=0)
{
	global $conf, $user, $langs, $db;
	global $object;

	$file_name = $dest_file;
	// If an upload error has been reported
	if ($uploaderrorcode)
	{
		switch($uploaderrorcode)
		{
			case UPLOAD_ERR_INI_SIZE:	// 1
				return 'ErrorFileSizeTooLarge';
				break;
			case UPLOAD_ERR_FORM_SIZE:	// 2
				return 'ErrorFileSizeTooLarge';
				break;
			case UPLOAD_ERR_PARTIAL:	// 3
				return 'ErrorPartialFile';
				break;
			case UPLOAD_ERR_NO_TMP_DIR:	//
				return 'ErrorNoTmpDir';
				break;
			case UPLOAD_ERR_CANT_WRITE:
				return 'ErrorFailedToWriteInDir';
				break;
			case UPLOAD_ERR_EXTENSION:
				return 'ErrorUploadBlockedByAddon';
				break;
			default:
				break;
		}
	}

	// If we need to make a virus scan
	if (empty($disablevirusscan) && file_exists($src_file) && ! empty($conf->global->MAIN_ANTIVIRUS_COMMAND))
	{
		require_once(DOL_DOCUMENT_ROOT.'/lib/security.lib.php');
		require_once(DOL_DOCUMENT_ROOT.'/lib/antivir.class.php');
		$antivir=new AntiVir($db);
		$result = $antivir->dol_avscan_file($src_file);
		if ($result < 0)	// If virus or error, we stop here
		{
			$reterrors=$antivir->errors;
			dol_syslog('Functions.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$file_name.'") KO with antivirus: result='.$result.' errors='.join(',',$antivir->errors), LOG_WARNING);
			return 'ErrorFileIsInfectedWithAVirus: '.join(',',$reterrors);
		}
	}

	// Security:
	// Disallow file with some extensions. We renamed them.
	// 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.
	if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$file_name))
	{
		$file_name.= '.noexe';
	}

	// Security:
	// On interdit fichiers caches, remontees de repertoire ainsi que les pipes dans les noms de fichiers.
	if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file))
	{
		dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
		return -1;
	}

	// Security:
	// On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans
	// les noms de fichiers.
	if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file))
	{
		dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
		return -2;
	}

	// The file functions must be in OS filesystem encoding.
	$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("Functions.lib::dol_move_uploaded_file File ".$file_name." already exists", 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("Functions.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG);

		if (! $notrigger && 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
		}

		return 1;	// Success
	}
	else
	{
		dol_syslog("Functions.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR);
		return -3;	// Unknown error
	}

	return 1;
}