This commit is contained in:
Roly Rudy Gutierrez Pinto
2019-02-27 19:48:45 -04:00
parent 04d4cefa24
commit e17d8f4f0e
10 changed files with 282 additions and 54 deletions

View File

@@ -1,7 +1,10 @@
<?php
namespace ProcessMaker\BusinessModel;
use G;
use Exception;
use PmDynaform;
use ProcessMaker\Util\PhpShorthandByte;
class InputDocument
{
@@ -288,7 +291,10 @@ class InputDocument
* @param string $processUid Unique id of Process
* @param array $arrayData Data
*
* return array Return data of the new InputDocument created
* @return array Return data of the new InputDocument created
*
* @see \ProcessMaker\Services\Api\Project\InputDocument->doPostInputDocument()
* @link https://wiki.processmaker.com/3.0/Input_Documents#Creating_Input_Documents
*/
public function create($processUid, $arrayData)
{
@@ -310,6 +316,8 @@ class InputDocument
$flagDataDestinationPath = (isset($arrayData["INP_DOC_DESTINATION_PATH"]))? 1 : 0;
$flagDataTags = (isset($arrayData["INP_DOC_TAGS"]))? 1 : 0;
$this->throwExceptionIfMaximumFileSizeExceed(intval($arrayData["INP_DOC_MAX_FILESIZE"]), $arrayData["INP_DOC_MAX_FILESIZE_UNIT"]);
//Create
$inputDocument = new \InputDocument();
@@ -348,8 +356,11 @@ class InputDocument
*
* @param string $inputDocumentUid Unique id of InputDocument
* @param array $arrayData Data
*
* return array Return data of the InputDocument updated
*
* @return array Return data of the InputDocument updated
*
* @see \ProcessMaker\Services\Api\Project\InputDocument->doPutInputDocument()
* @link https://wiki.processmaker.com/3.0/Input_Documents#Creating_Input_Documents
*/
public function update($inputDocumentUid, $arrayData)
{
@@ -374,6 +385,8 @@ class InputDocument
if (isset($arrayData["INP_DOC_TITLE"])) {
$this->throwExceptionIfExistsTitle($processUid, $arrayData["INP_DOC_TITLE"], $this->arrayFieldNameForException["inputDocumentTitle"], $inputDocumentUid);
}
$this->throwExceptionIfMaximumFileSizeExceed(intval($arrayData["INP_DOC_MAX_FILESIZE"]), $arrayData["INP_DOC_MAX_FILESIZE_UNIT"]);
//Update
$arrayData["INP_DOC_UID"] = $inputDocumentUid;
@@ -519,7 +532,7 @@ class InputDocument
*
* @param string $inputDocumentUid Unique id of InputDocument
*
* return array Return an array with data of an InputDocument
* @return array Return an array with data of an InputDocument
*/
public function getInputDocument($inputDocumentUid)
{
@@ -544,5 +557,71 @@ class InputDocument
throw $e;
}
}
/**
* Throw exception if maximum file size exceed to php directives.
*
* @param int $value
* @param string $unit
* @throws Exception
*
* @see ProcessMaker\BusinessModel\InputDocument->create()
* @see ProcessMaker\BusinessModel\InputDocument->update()
* @link https://wiki.processmaker.com/3.2/Input_Documents
*/
public function throwExceptionIfMaximumFileSizeExceed($value, $unit)
{
//The value of 'INP_DOC_MAX_FILESIZE_UNIT' can only take two values: 'KB'and 'MB'.
if ($unit === "MB") {
$value = $value * (1024 ** 2);
}
if ($unit === "KB") {
$value = $value * (1024 ** 1);
}
$object = $this->getMaxFileSize();
if ($object->uploadMaxFileSizeBytes < $value) {
throw new Exception(G::LoadTranslation("ID_THE_MAXIMUM_VALUE_OF_THIS_FIELD_IS", [$object->uploadMaxFileSize]));
}
}
/**
* To upload large files, post_max_size value must be larger than upload_max_filesize.
* Generally speaking, memory_limit should be larger than post_max_size. When an integer
* is used, the value is measured in bytes. The shorthand notation may also be used.
* If the size of post data is greater than post_max_size, the $_POST and $_FILES
* superglobals are empty.
*
* @return object
*
* @see ProcessMaker\BusinessModel\InputDocument->throwExceptionIfMaximumFileSizeExceed()
* @link https://wiki.processmaker.com/3.2/Input_Documents
* @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes
*/
public function getMaxFileSize()
{
$phpShorthandByte = new PhpShorthandByte();
$postMaxSize = ini_get("post_max_size");
$postMaxSizeBytes = $phpShorthandByte->valueToBytes($postMaxSize);
$uploadMaxFileSize = ini_get("upload_max_filesize");
$uploadMaxFileSizeBytes = $phpShorthandByte->valueToBytes($uploadMaxFileSize);
if ($postMaxSizeBytes < $uploadMaxFileSizeBytes) {
$uploadMaxFileSize = $postMaxSize;
$uploadMaxFileSizeBytes = $postMaxSizeBytes;
}
//according to the acceptance criteria the information is always shown in MBytes
$uploadMaxFileSizeMBytes = $uploadMaxFileSizeBytes / (1024 ** 2); //conversion constant
$uploadMaxFileSizeUnit = "MB"; //short processmaker notation, https://wiki.processmaker.com/3.0/File_control#Size_Unity
$uploadMaxFileSizePhpUnit = "M"; //short php notation, http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes
$result = [
"uploadMaxFileSize" => $phpShorthandByte->getFormatBytes($uploadMaxFileSizeMBytes . $uploadMaxFileSizePhpUnit),
"uploadMaxFileSizeBytes" => $uploadMaxFileSizeBytes,
"uploadMaxFileSizeMBytes" => $uploadMaxFileSizeMBytes,
"uploadMaxFileSizeUnit" => $uploadMaxFileSizeUnit
];
return (object) $result;
}
}

View File

@@ -1490,6 +1490,7 @@ class Light
}
$response['listLanguage'] = $languagesList;
if (isset($params['fileLimit']) && $params['fileLimit']) {
//to do: ProcessMaker\BusinessModel\InputDocument->getMaxFileSize()
$postMaxSize = $this->return_bytes(ini_get('post_max_size'));
$uploadMaxFileSize = $this->return_bytes(ini_get('upload_max_filesize'));
if ($postMaxSize < $uploadMaxFileSize) {

View File

@@ -0,0 +1,82 @@
<?php
namespace ProcessMaker\Util;
class PhpShorthandByte
{
private $units;
private $terminal;
/**
* Constructor.
* Supported format php directives:
* [number]G
* [number]K
* [number]M
*/
function __construct()
{
$this->units = ['K', 'M', 'G'];
$this->terminal = "bytes";
}
/**
* Convert value string to bytes, for directives php.ini
*
* @param string $value
* @return integer
*
* @see ProcessMaker\BusinessModel\InputDocument->getMaxFileSize()
* @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes
*/
public function valueToBytes($value)
{
foreach ($this->units as $i => $unit) {
$number = $this->getNumberValue($value, $unit);
if ($number !== null) {
$result = $number * (1024 ** ($i + 1));
return $result;
}
}
return intval($value);
}
/**
* Get number value and validate expresion.
* Valid expresion is: [number][unit]
*
* @param string $string
* @param string $unit
* @return integer|null
*
* @see ProcessMaker\Util\PhpShorthandByte->valueToBytes()
* @link http://php.net/manual/en/faq.using.php#faq.using.shorthandbytes
*/
public function getNumberValue($string, $unit)
{
$string = preg_replace('/\s+/', '', $string);
$isCorrect = preg_match("/\d+{$unit}/", $string);
if ($isCorrect === 1) {
$result = rtrim($string, $unit);
return intval($result);
}
return null;
}
/**
* Get format bytes.
*
* @param string $value
* @return string
*/
public function getFormatBytes($value)
{
foreach ($this->units as $i => $unit) {
$number = $this->getNumberValue($value, $unit);
if ($number !== null) {
return $number . " " . $unit . $this->terminal;
}
}
return $value;
}
}

View File

@@ -8,6 +8,7 @@ use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Cache;
use ProcessMaker\Core\System;
use ProcessMaker\Services\OAuth2\Server;
use ProcessMaker\Util\PhpShorthandByte;
use Symfony\Component\HttpFoundation\File\File;
class ValidationUploadedFiles
@@ -169,6 +170,8 @@ class ValidationUploadedFiles
* File upload validation.
*
* @return $this
*
* @see workflow/public_html/sysGeneric.php
*/
public function runRulesToAllUploadedFiles()
{
@@ -177,6 +180,12 @@ class ValidationUploadedFiles
return;
}
$this->fails = [];
$validator = $this->runRulesForFileEmpty();
if ($validator->fails()) {
$this->fails[] = $validator;
}
foreach ($files as $file) {
$data = (object) $file;
if (!is_array($data->name) || !is_array($data->tmp_name)) {
@@ -207,9 +216,70 @@ class ValidationUploadedFiles
}
}
}
return $this;
}
/**
* Run rules if files is empty.
*
* @see ProcessMaker\Validation\ValidationUploadedFiles->runRulesToAllUploadedFiles()
* @see Luracast\Restler\Format\UploadFormat->decode()
*/
public function runRulesForFileEmpty()
{
$validator = new Validator();
//rule: validate $_SERVER['CONTENT_LENGTH']
$rule = $validator->addRule();
$rule->validate(null, function($file) use ($rule) {
//according to the acceptance criteria the information is always shown in MBytes
$phpShorthandByte = new PhpShorthandByte();
$postMaxSize = ini_get("post_max_size");
$postMaxSizeBytes = $phpShorthandByte->valueToBytes($postMaxSize);
$uploadMaxFileSize = ini_get("upload_max_filesize");
$uploadMaxFileSizeBytes = $phpShorthandByte->valueToBytes($uploadMaxFileSize);
if ($postMaxSizeBytes < $uploadMaxFileSizeBytes) {
$uploadMaxFileSize = $postMaxSize;
$uploadMaxFileSizeBytes = $postMaxSizeBytes;
}
//according to the acceptance criteria the information is always shown in MBytes
$uploadMaxFileSizeMBytes = $uploadMaxFileSizeBytes / (1024 ** 2); //conversion constant
$message = G::LoadTranslation('ID_THE_FILE_SIZE_IS_BIGGER_THAN_THE_MAXIMUM_ALLOWED', [$uploadMaxFileSizeMBytes]);
$rule->message($message);
/**
* If you can, you may want to set post_max_size to a low value (say 1M) to make
* testing easier. First test to see how your script behaves. Try uploading a file
* that is larger than post_max_size. If you do you will get a message like this
* in your error log:
*
* [09-Jun-2010 19:28:01] PHP Warning: POST Content-Length of 30980857 bytes exceeds
* the limit of 2097152 bytes in Unknown on line 0
*
* This makes the script is not completed.
*
* Solving the problem:
* The PHP documentation http://php.net/manual/en/ini.core.php#ini.post-max-size
* provides a hack to solve this problem:
*
* If the size of post data is greater than post_max_size, the $_POST and $_FILES
* superglobals are empty.
*/
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0) {
return true;
}
return false;
})
->status(400)
->log(function($rule) {
Bootstrap::registerMonologPhpUploadExecution('phpUpload', 400, $rule->getMessage(), "");
});
return $validator->validate();
}
/**
* Get the first error and call the argument function.
*