2023-02-02 12:30:32 +00:00
< ? php
2026-03-02 02:35:00 +00:00
/* Copyright ( C ) 2023 - 2026 Laurent Destailleur < eldy @ users . sourceforge . net >
2024-03-23 00:12:23 +00:00
* Copyright ( C ) 2024 MDW < mdeweerd @ users . noreply . github . com >
2024-09-05 14:05:37 +00:00
* Copyright ( C ) 2024 Frédéric France < frederic . france @ free . fr >
2023-02-02 12:30:32 +00:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*/
/**
2023-03-27 09:52:56 +00:00
* \file htdocs / core / ajax / flowjs - server . php
* \brief File to upload very large file , higher than PHP limit . Using flowjs library .
2023-02-02 12:30:32 +00:00
*/
if ( ! defined ( 'NOTOKENRENEWAL' )) {
define ( 'NOTOKENRENEWAL' , '1' ); // Disables token renewal
}
2026-03-02 02:35:00 +00:00
// If there is no need to load and show top and left menu
2023-02-02 12:30:32 +00:00
if ( ! defined ( 'NOREQUIREMENU' )) {
define ( 'NOREQUIREMENU' , '1' );
}
if ( ! defined ( 'NOREQUIREHTML' )) {
define ( 'NOREQUIREHTML' , '1' );
}
if ( ! defined ( 'NOREQUIREAJAX' )) {
define ( 'NOREQUIREAJAX' , '1' );
}
if ( ! defined ( 'NOREQUIRESOC' )) {
define ( 'NOREQUIRESOC' , '1' );
}
2023-02-06 11:24:19 +00:00
if ( ! defined ( " NOLOGIN " )) {
define ( " NOLOGIN " , '1' );
}
2023-02-02 12:30:32 +00:00
//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); // Required to know date format for dol_print_date
// Load Dolibarr environment
require '../../main.inc.php' ;
2023-02-21 14:18:27 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2023-02-02 12:30:32 +00:00
2024-11-04 22:53:20 +00:00
/**
* @ var Conf $conf
* @ var DoliDB $db
* @ var HookManager $hookmanager
* @ var Translate $langs
* @ var User $user
*/
2023-02-02 12:30:32 +00:00
$action = GETPOST ( 'action' , 'aZ09' );
2023-03-27 09:52:56 +00:00
$module = GETPOST ( 'module' , 'aZ09arobase' );
2025-06-04 14:20:04 +00:00
$uploaddirname = dol_sanitizeFileName ( GETPOST ( 'uploaddirname' , 'alpha' ));
2023-03-27 09:52:56 +00:00
2023-02-02 12:30:32 +00:00
$flowFilename = GETPOST ( 'flowFilename' , 'alpha' );
$flowIdentifier = GETPOST ( 'flowIdentifier' , 'alpha' );
$flowChunkNumber = GETPOST ( 'flowChunkNumber' , 'alpha' );
$flowChunkSize = GETPOST ( 'flowChunkSize' , 'alpha' );
$flowTotalSize = GETPOST ( 'flowTotalSize' , 'alpha' );
2026-03-02 02:35:00 +00:00
$result = restrictedArea ( $user , ( $module ? $module : 'unknown' ), 0 , '' , '' , 'fk_soc' , 'rowid' , 0 , 1 ); // Call with mode return. Use 'unknown' if module not defined to be sure to have an error when module is not set
if ( ! $result ) {
httponly_accessforbidden ( " No permission on module " . $module );
}
2023-03-27 09:52:56 +00:00
if ( $action != 'upload' ) {
httponly_accessforbidden ( " Param action must be 'upload' " );
}
if ( ! empty ( $conf -> $module -> dir_temp )) {
$upload_dir = $conf -> $module -> dir_temp ;
2025-06-04 14:20:04 +00:00
if ( ! empty ( $uploaddirname )) {
$upload_dir .= " / " . $uploaddirname ;
}
2023-03-27 09:52:56 +00:00
} else {
httponly_accessforbidden ( " Param module does not has a dir_temp directory. Module does not exists or is not activated. " );
}
2026-03-02 02:35:00 +00:00
2023-02-02 12:30:32 +00:00
/*
* Action
*/
top_httphead ();
2023-03-27 09:52:56 +00:00
2023-02-24 11:20:39 +00:00
$result = false ;
2023-02-15 14:06:32 +00:00
if ( ! empty ( $upload_dir )) {
$temp_dir = $upload_dir . '/' . $flowIdentifier ;
} else {
2023-02-02 12:30:32 +00:00
$temp_dir = DOL_DATA_ROOT . '/' . $module . '/temp/' . $flowIdentifier ;
2023-02-23 10:20:19 +00:00
$upload_dir = DOL_DATA_ROOT . '/' . $module . '/temp/' ;
2023-02-15 14:06:32 +00:00
}
2023-02-24 11:20:39 +00:00
if ( $module != " test " && ! isModEnabled ( $module )) {
echo json_encode ( " The module " . $module . " is not enabled " );
header ( " HTTP/1.0 400 " );
die ();
}
2023-02-15 14:16:18 +00:00
if ( $_SERVER [ 'REQUEST_METHOD' ] === 'GET' ) {
2023-02-02 12:30:32 +00:00
$chunk_file = $temp_dir . '/' . $flowFilename . '.part' . $flowChunkNumber ;
if ( file_exists ( $chunk_file )) {
2023-12-04 11:04:36 +00:00
header ( " HTTP/1.0 200 Ok " );
2023-02-02 12:30:32 +00:00
} else {
header ( " HTTP/1.0 404 Not Found " );
}
2023-02-15 14:06:32 +00:00
} else {
// loop through files and move the chunks to a temporarily created directory
2023-02-16 11:01:34 +00:00
if ( file_exists ( $upload_dir . '/' . $flowFilename )) {
echo json_encode ( 'File ' . $flowIdentifier . ' was already uploaded' );
header ( " HTTP/1.0 200 Ok " );
2023-02-24 11:20:39 +00:00
die ();
2023-12-04 11:04:36 +00:00
} elseif ( ! empty ( $_FILES )) {
foreach ( $_FILES as $file ) {
// check the error status
if ( $file [ 'error' ] != 0 ) {
dol_syslog ( 'error ' . $file [ 'error' ] . ' in file ' . $flowFilename );
continue ;
}
// init the destination file (format <filename.ext>.part<#chunk>
// the file is stored in a temporary directory
$dest_file = $temp_dir . '/' . $flowFilename . '.part' . $flowChunkNumber ;
// create the temporary directory
if ( ! dol_is_dir ( $temp_dir )) {
dol_mkdir ( $temp_dir );
}
// move the temporary file
if ( ! dol_move_uploaded_file ( $file [ 'tmp_name' ], $dest_file , 0 )) {
dol_syslog ( 'Error saving (move_uploaded_file) chunk ' . $flowChunkNumber . ' for file ' . $flowFilename );
} else {
// check if all the parts present, and create the final destination file
$result = createFileFromChunks ( $temp_dir , $upload_dir , $flowFilename , $flowChunkSize , $flowTotalSize );
}
2023-02-15 14:06:32 +00:00
}
2023-02-02 12:30:32 +00:00
}
}
2023-02-15 14:06:32 +00:00
if ( $result ) {
echo json_encode ( 'File ' . $flowIdentifier . ' uploaded' );
} else {
echo json_encode ( 'Error while uploading file ' . $flowIdentifier );
}
2023-02-02 12:30:32 +00:00
/**
2023-03-27 09:52:56 +00:00
* Check if all the parts exist , and gather all the parts of the file together .
*
* @ param string $temp_dir the temporary directory holding all the parts of the file
* @ param string $upload_dir the temporary directory to create file
* @ param string $fileName the original file name
* @ param string $chunkSize each chunk size ( in bytes )
* @ param string $totalSize original file size ( in bytes )
* @ return bool true if Ok false else
2023-02-02 12:30:32 +00:00
*/
2023-02-15 14:06:32 +00:00
function createFileFromChunks ( $temp_dir , $upload_dir , $fileName , $chunkSize , $totalSize )
2023-02-02 12:30:32 +00:00
{
2023-10-20 09:20:02 +00:00
dol_syslog ( __FUNCTION__ , LOG_DEBUG );
2023-03-27 09:52:56 +00:00
2023-02-02 12:30:32 +00:00
// count all the parts of this file
$total_files = 0 ;
$files = dol_dir_list ( $temp_dir , 'files' );
foreach ( $files as $file ) {
2023-02-23 10:20:19 +00:00
if ( stripos ( $file [ " name " ], $fileName ) !== false ) {
2023-02-02 12:30:32 +00:00
$total_files ++ ;
}
}
// check that all the parts are present
// the size of the last part is between chunkSize and 2*$chunkSize
2024-03-23 00:12:23 +00:00
if ( $total_files * ( float ) $chunkSize >= (( float ) $totalSize - ( float ) $chunkSize + 1 )) {
2023-02-02 12:30:32 +00:00
// create the final destination file
2023-02-15 14:06:32 +00:00
if (( $fp = fopen ( $upload_dir . '/' . $fileName , 'w' )) !== false ) {
2024-03-23 00:12:23 +00:00
for ( $i = 1 ; $i <= $total_files ; $i ++ ) {
2023-02-02 12:30:32 +00:00
fwrite ( $fp , file_get_contents ( $temp_dir . '/' . $fileName . '.part' . $i ));
dol_syslog ( 'writing chunk ' . $i );
}
fclose ( $fp );
} else {
dol_syslog ( 'cannot create the destination file' );
return false ;
}
2023-02-15 14:06:32 +00:00
// rename the temporary directory (to avoid access from other
// concurrent chunks uploads)
@ rename ( $temp_dir , $temp_dir . '_UNUSED' );
2023-02-02 12:30:32 +00:00
}
2023-03-27 09:52:56 +00:00
2023-02-02 12:30:32 +00:00
return true ;
}