static function SaveFile($arFile, $strSavePath, $forceRandom = false, $skipExtension = false, $dirAdd = '')
{
$strFileName = GetFileName($arFile["name"] ?? ''); /* filename.gif */
if(isset($arFile["del"]) && $arFile["del"] <> '')
{
static::Delete($arFile["old_file"] ?? 0);
if($strFileName == '')
return "NULL";
}
if(!isset($arFile["name"]) || $arFile["name"] == '')
{
if(isset($arFile["description"]) && intval($arFile["old_file"])>0)
{
static::UpdateDesc($arFile["old_file"], $arFile["description"]);
}
return false;
}
if (isset($arFile["content"]))
{
if (!isset($arFile["size"]))
{
$arFile["size"] = strlen($arFile["content"]);
}
}
else
{
try
{
$file = new IOFile(IOPath::convertPhysicalToLogical($arFile["tmp_name"]));
$arFile["size"] = $file->getSize();
}
catch(IOIoException $e)
{
$arFile["size"] = 0;
}
}
$arFile["ORIGINAL_NAME"] = $strFileName;
//translit, replace unsafe chars, etc.
$strFileName = self::transformName($strFileName, $forceRandom, $skipExtension);
//transformed name must be valid, check disk quota, etc.
if (self::validateFile($strFileName, $arFile) !== "")
{
return false;
}
$arFile["type"] = WebMimeType::normalize($arFile["type"]);
$original = null;
$io = CBXVirtualIo::GetInstance();
$bExternalStorage = false;
foreach(GetModuleEvents("main", "OnFileSave", true) as $arEvent)
{
if(ExecuteModuleEventEx($arEvent, array(&$arFile, $strFileName, $strSavePath, $forceRandom, $skipExtension, $dirAdd)))
{
$bExternalStorage = true;
break;
}
}
if(!$bExternalStorage)
{
// we should keep number of files in a folder below 10,000
// three chars from md5 give us 4096 subdirs
$upload_dir = COption::GetOptionString("main", "upload_dir", "upload");
if($forceRandom != true && COption::GetOptionString("main", "save_original_file_name", "N") == "Y")
{
//original name
$subdir = $dirAdd;
if($subdir == '')
{
while(true)
{
$random = SecurityRandom::getString(32);
$subdir = substr(md5($random), 0, 3)."/".$random;
if(!$io->FileExists($_SERVER["DOCUMENT_ROOT"]."/".$upload_dir."/".$strSavePath."/".$subdir."/".$strFileName))
{
break;
}
}
}
$strSavePath = rtrim($strSavePath, "/")."/".$subdir;
}
else
{
//random name
$fileExtension = ($skipExtension == true || ($ext = GetFileExtension($strFileName)) == ''? '' : ".".$ext);
while(true)
{
$subdir = substr(md5($strFileName), 0, 3);
$strSavePath = rtrim($strSavePath, "/")."/".$subdir;
if(!$io->FileExists($_SERVER["DOCUMENT_ROOT"]."/".$upload_dir."/".$strSavePath."/".$strFileName))
{
break;
}
//try the new name
$strFileName = SecurityRandom::getString(32).$fileExtension;
}
}
$arFile["SUBDIR"] = $strSavePath;
$arFile["FILE_NAME"] = $strFileName;
$dirName = $_SERVER["DOCUMENT_ROOT"]."/".$upload_dir."/".$strSavePath."/";
$physicalFileName = $io->GetPhysicalName($dirName.$strFileName);
CheckDirPath($dirName);
if(is_set($arFile, "content"))
{
if(file_put_contents($physicalFileName, $arFile["content"]) === false)
{
return false;
}
}
else
{
if(!copy($arFile["tmp_name"], $physicalFileName) && !move_uploaded_file($arFile["tmp_name"], $physicalFileName))
{
return false;
}
}
if(isset($arFile["old_file"]))
{
static::Delete($arFile["old_file"]);
}
@chmod($physicalFileName, BX_FILE_PERMISSIONS);
//flash is not an image
$flashEnabled = !static::IsImage($arFile["ORIGINAL_NAME"], $arFile["type"]);
$image = new FileImage($physicalFileName);
$imgInfo = $image->getInfo($flashEnabled);
if($imgInfo)
{
$arFile["WIDTH"] = $imgInfo->getWidth();
$arFile["HEIGHT"] = $imgInfo->getHeight();
if ($imgInfo->getFormat() == FileImage::FORMAT_JPEG && empty($arFile['no_rotate']) && !$image->exceedsMaxSize())
{
$exifData = $image->getExifData();
if (isset($exifData['Orientation']) && $exifData['Orientation'] > 1)
{
if($image->load())
{
if($image->autoRotate($exifData['Orientation']))
{
$quality = COption::GetOptionString('main', 'image_resize_quality');
if($image->save($quality))
{
// update width and height
$arFile['WIDTH'] = $image->getWidth();
$arFile['HEIGHT'] = $image->getHeight();
$arFile['size'] = filesize($physicalFileName);
}
}
}
}
}
}
else
{
$arFile["WIDTH"] = 0;
$arFile["HEIGHT"] = 0;
}
//calculate a hash for the control of duplicates
$arFile["FILE_HASH"] = static::CalculateHash($physicalFileName, $arFile["size"]);
//control of duplicates
if ($arFile["FILE_HASH"] <> '')
{
$lockId = static::lockFileHash($arFile["size"], $arFile["FILE_HASH"]);
$original = static::FindDuplicate($arFile["size"], $arFile["FILE_HASH"]);
if($original !== null)
{
//points to the original's physical path
$arFile["SUBDIR"] = $original->getFile()->getSubdir();
$arFile["FILE_NAME"] = $original->getFile()->getFileName();
$originalPath = $_SERVER["DOCUMENT_ROOT"]."/".$upload_dir."/".$arFile["SUBDIR"]."/".$arFile["FILE_NAME"];
if($physicalFileName <> $io->GetPhysicalName($originalPath))
{
unlink($physicalFileName);
try
{
rmdir($io->GetPhysicalName($dirName));
}
catch (ErrorException $exception)
{
// Ignore a E_WARNING Error
}
}
}
}
}
else
{
//from clouds
if(isset($arFile["original_file"]) && $arFile["original_file"] instanceof InternalEO_FileHash)
{
$original = $arFile["original_file"];
}
}
if($arFile["WIDTH"] == 0 || $arFile["HEIGHT"] == 0)
{
//mock image because we got false from CFile::GetImageSize()
if(strpos($arFile["type"], "image/") === 0 && $arFile["type"] <> 'image/svg+xml')
{
$arFile["type"] = "application/octet-stream";
}
}
/****************************** QUOTA ******************************/
if (COption::GetOptionInt("main", "disk_space") > 0 && $original === null)
{
CDiskQuota::updateDiskQuota("file", $arFile["size"], "insert");
}
/****************************** QUOTA ******************************/
$NEW_IMAGE_ID = static::DoInsert(array(
"HEIGHT" => $arFile["HEIGHT"],
"WIDTH" => $arFile["WIDTH"],
"FILE_SIZE" => $arFile["size"],
"CONTENT_TYPE" => $arFile["type"],
"SUBDIR" => $arFile["SUBDIR"],
"FILE_NAME" => $arFile["FILE_NAME"],
"MODULE_ID" => $arFile["MODULE_ID"] ?? '',
"ORIGINAL_NAME" => $arFile["ORIGINAL_NAME"],
"DESCRIPTION" => ($arFile["description"] ?? ''),
"HANDLER_ID" => ($arFile["HANDLER_ID"] ?? ''),
"EXTERNAL_ID" => ($arFile["external_id"] ?? md5(mt_rand())),
"FILE_HASH" => ($original === null? $arFile["FILE_HASH"] : ''),
));
if (isset($lockId))
{
static::unlockFileHash($lockId);
}
if($original !== null)
{
//save information about the duplicate for future use (on deletion)
static::AddDuplicate($original->getFileId(), $NEW_IMAGE_ID, false);
}
static::CleanCache($NEW_IMAGE_ID);
return $NEW_IMAGE_ID;
}