diff --git a/htdocs/accountancy/admin/categories_list.php b/htdocs/accountancy/admin/categories_list.php index 86be6aa52abd2fe44a84723b696915c1e31f1406..c0fa895ae4ce5c838ff54583afe3311c8cef7e5e 100644 --- a/htdocs/accountancy/admin/categories_list.php +++ b/htdocs/accountancy/admin/categories_list.php @@ -929,7 +929,7 @@ if ($id) { print '<td align="center">'; if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>'; - //else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin + //else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin print '</td>'; } else print '<td> </td>'; diff --git a/htdocs/accountancy/admin/journals_list.php b/htdocs/accountancy/admin/journals_list.php index facb507c530e8b64f2dcad708df7d437d8479050..1421d71be970a6214d6b34d85ec7bfb2f7c0ad13 100644 --- a/htdocs/accountancy/admin/journals_list.php +++ b/htdocs/accountancy/admin/journals_list.php @@ -676,7 +676,7 @@ if ($id) { print '<td align="center">'; if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>'; - //else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin + //else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin print '</td>'; } else print '<td> </td>'; diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 8319ccd045037f2c3f8260a42a9021022576f234..28db9ef8b49bfc3363708029da62ecfa052a61f7 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -1100,7 +1100,7 @@ if ($id) $reshook=$hookmanager->executeHooks('createDictionaryFieldlist',$parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks $error=$hookmanager->error; $errors=$hookmanager->errors; - if ($id == 3) unset($fieldlist[2]); // Remove field ??? if dictionnary Regions + if ($id == 3) unset($fieldlist[2]); // Remove field ??? if dictionary Regions if (empty($reshook)) { @@ -1555,7 +1555,7 @@ if ($id) { print '<td align="center">'; if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>'; - //else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin + //else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin print '</td>'; } else print '<td> </td>'; diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index a403cf1f4933035720059c472ced9a8ad68e1d46..b9e5df738adf26a48ab661c3842d7fec46f26469 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -767,7 +767,7 @@ if ($resql) { print '<td align="center">'; if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>'; - //else print '<a href="#">'.img_delete().'</a>'; // Some dictionnary can be edited by other profile than admin + //else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin print '</td>'; } else print '<td> </td>'; diff --git a/htdocs/api/admin/explorer.php b/htdocs/api/admin/explorer.php index c83d759dcd6a8be1acd4d64c3bbf0bf9c5e18c82..b09acb6772aff723f3fd762bb1e6ab9e4ebc4409 100644 --- a/htdocs/api/admin/explorer.php +++ b/htdocs/api/admin/explorer.php @@ -14,6 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @deprecated Old explorer. Not using Swagger. See instead explorer in htdocs/api/index.php. */ /** diff --git a/htdocs/api/class/api_dictionnarycountries.class.php b/htdocs/api/class/api_dictionarycountries.class.php similarity index 97% rename from htdocs/api/class/api_dictionnarycountries.class.php rename to htdocs/api/class/api_dictionarycountries.class.php index ddb3e2474a9e6aca5b3a5726cf2d1b755295436d..070be509a8acf0deeafdd409bccf82a6ee6bedb7 100644 --- a/htdocs/api/class/api_dictionnarycountries.class.php +++ b/htdocs/api/class/api_dictionarycountries.class.php @@ -27,7 +27,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php'; * @access protected * @class DolibarrApiAccess {@requires user,external} */ -class DictionnaryCountries extends DolibarrApi +class DictionaryCountries extends DolibarrApi { private $translations = null; @@ -93,7 +93,8 @@ class DictionnaryCountries extends DolibarrApi if ($result) { $num = $this->db->num_rows($result); - for ($i = 0; $i < min($num, ($limit <= 0 ? $num : $limit)); $i++) { + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { $obj = $this->db->fetch_object($result); $country = new Ccountry($this->db); if ($country->fetch($obj->rowid) > 0) { diff --git a/htdocs/api/class/api_dictionnarytowns.class.php b/htdocs/api/class/api_dictionarytowns.class.php similarity index 95% rename from htdocs/api/class/api_dictionnarytowns.class.php rename to htdocs/api/class/api_dictionarytowns.class.php index da58c9109eb86ab5d5188eca02b2e1fde3996937..0ebcfbe0b17df1bc004b001e36cf800c99c7f396 100644 --- a/htdocs/api/class/api_dictionnarytowns.class.php +++ b/htdocs/api/class/api_dictionarytowns.class.php @@ -27,7 +27,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php'; * @access protected * @class DolibarrApiAccess {@requires user,external} */ -class DictionnaryTowns extends DolibarrApi +class DictionaryTowns extends DolibarrApi { /** * Constructor @@ -88,7 +88,8 @@ class DictionnaryTowns extends DolibarrApi if ($result) { $num = $this->db->num_rows($result); - for ($i = 0; $i < min($num, ($limit <= 0 ? $num : $limit)); $i++) { + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { $list[] = $this->db->fetch_object($result); } } else { diff --git a/htdocs/api/class/api_documents.class.php b/htdocs/api/class/api_documents.class.php index ca10b2befce87fe5ff2d8626dd1c9b281f32f5da..6650fc45401ad0f50e8ab7503486cc182c7dccb4 100644 --- a/htdocs/api/class/api_documents.class.php +++ b/htdocs/api/class/api_documents.class.php @@ -58,23 +58,33 @@ class Documents extends DolibarrApi * * @return array * @throws RestException - * */ + /* public function get($module_part, $filename) { - } + }*/ /** - * Receive file - * - * @param array $request_data Request datas + * Push a file. + * Test sample: { "filename": "mynewfile.txt", "modulepart": "facture", "ref": "FA1701-001", "subdir": "", "filecontent": "content text", "fileencoding": "" } * - * @return bool State of copy + * @param string $filename Name of file to create ('FA1705-0123') + * @param string $modulepart Module part ('facture', ...) + * @param string $ref Reference of object (This will define subdir automatically and store submited file into it) + * @param string $subdir Subdirectory (Only if refname not provided) + * @param string $filecontent File content (string with file content. An empty file will be created if this parameter is not provided) + * @param string $fileencoding File encoding (''=no encoding, 'base64'=Base 64) + * @return bool State of copy * @throws RestException */ - public function post($request_data) { - global $conf; + public function post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='') { + global $db, $conf; + + /*var_dump($modulepart); + var_dump($filename); + var_dump($filecontent); + exit;*/ require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; @@ -82,46 +92,89 @@ class Documents extends DolibarrApi throw new RestException(401); } - // Suppression de la chaine de caractere ../ dans $original_file - $original_file = str_replace("../","/", $request_data['name']); - $refname = str_replace("../","/", $request_data['refname']); + $newfilecontent = ''; + if (empty($fileencoding)) $newfilecontent = $filecontent; + if ($fileencoding == 'base64') $newfilecontent = base64_decode($filecontent); - // find the subdirectory name as the reference - if (empty($request_data['refname'])) $refname=basename(dirname($original_file)."/"); + $original_file = dol_sanitizeFileName($filename); - // Security: - // On interdit les remontees de repertoire ainsi que les pipe dans - // les noms de fichiers. - if (preg_match('/\.\./',$original_file) || preg_match('/[<>|]/',$original_file)) + // Define $uploadir + $object = null; + $entity = $user->entity; + if ($ref) { - throw new RestException(401,'Refused to deliver file '.$original_file); + if ($modulepart == 'facture' || $modulepart == 'invoice') + { + $modulepart='facture'; + $object=new Facture($db); + $result = $object->fetch('', $ref); + if (! ($result > 0)) + { + throw new RestException(500, 'The object '.$modulepart." with ref '".$ref."' was not found."); + } + if (! empty($entity)) + { + $tmpreldir = get_exdir(0, 0, 0, 0, $object, $modulepart); + $upload_dir = $conf->{$modulepart}->multidir_output[$entity].'/'.$tmpreldir.$object->ref; + } + else + { + $tmpreldir = get_exdir(0, 0, 0, 0, $object, $modulepart); + $upload_dir = $conf->{$modulepart}->dir_output.'/'.$tmpreldir.$object->ref; + } + } + + if (empty($upload_dir) || $upload_dir == '/') + { + throw new RestException(500, 'This value of modulepart does not support yet usage of refname. Check modulepart parameter or try to use subdir parameter instead of ref.'); + } } - if (preg_match('/\.\./',$refname) || preg_match('/[<>|]/',$refname)) + else { - throw new RestException(401,'Refused to deliver file '.$refname); + if ($modulepart == 'invoice') $modulepart ='facture'; + if (empty($conf->{$modulepart}->dir_output)) + { + throw new RestException(500, 'This value of modulepart is not supported with refname not defined.'); + } + $upload_dir = $conf->{$modulepart}->multidir_output[$entity]; + + if (empty($upload_dir) || $upload_dir == '/') + { + throw new RestException(500, 'This value of modulepart is not yet supported.'); + } } - - $modulepart = $request_data['modulepart']; + $upload_dir = dol_sanitizePathName($upload_dir); + + // Security: + // TODO Use dol_check_secure_access_document // Check mandatory fields - $result = $this->_validate_file($request_data); + //$result = $this->_validate_file($request_data); - $upload_dir = DOL_DATA_ROOT . '/' .$modulepart.'/'.dol_sanitizeFileName($refname); - $destfile = $upload_dir . $original_file; + $destfile = $upload_dir . '/' . $original_file; - if (!is_dir($upload_dir)) { + if (!dol_is_dir($upload_dir)) { throw new RestException(401,'Directory not exists : '.$upload_dir); } - $file = $_FILES['file']; - $srcfile = $file['tmp_name']; - $res = dol_move($srcfile, $destfile, 0, 1); - - if (!$res) { - throw new RestException(500); + if (dol_is_file($destfile)) + { + throw new RestException(500, "File with name '".$original_file."' already exists."); } - - return $res; + + $fhandle = fopen($destfile, 'w'); + if ($fhandle) + { + $nbofbyteswrote = fwrite($fhandle, $newfilecontent); + fclose($fhandle); + @chmod($destfile, octdec($conf->global->MAIN_UMASK)); + } + else + { + throw new RestException(500, 'Failed to open file for write'); + } + + return true; } /** diff --git a/htdocs/api/class/api_login.class.php b/htdocs/api/class/api_login.class.php index 76a9befebc997a9e00003f1dc56db824e479638b..9b965e24c3362609c73a2df5f72499634d255ab0 100644 --- a/htdocs/api/class/api_login.class.php +++ b/htdocs/api/class/api_login.class.php @@ -36,7 +36,7 @@ class Login * * Request the API token for a couple username / password. * Using method POST is recommanded for security reasons (method GET is often logged by default by web servers with parameters so with login and pass into server log file). - * Both method are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page). + * Both methods are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page). * * @param string $login User login * @param string $password User password diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 26001e8e1f13c83e283cb5cf8be0d1ce1a327a32..f58e96087b897aa720b78ff9d1b27444c970ecd6 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -2502,7 +2502,7 @@ class Form } if ($objp->supplier_reputation) { - //TODO dictionnary + //TODO dictionary $reputations=array(''=>$langs->trans('Standard'),'FAVORITE'=>$langs->trans('Favorite'),'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier')); $opt .= " - ".$reputations[$objp->supplier_reputation]; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 09856131da78646cda107312eca8a215eaa8f9ca..2d3b1420e81d9c6baaeb7cc1d15210d8a123eba6 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -4555,8 +4555,8 @@ function yn($yesno, $case=1, $color=0) /** * Return a path to have a directory according to object. - * New usage: $conf->module->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'modulepart') - * or: $conf->module->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, 'modulepart') if multidir_output not defined. + * New usage: $conf->module->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, $modulepart) + * or: $conf->module->dir_output.'/'.get_exdir(0, 0, 0, 1, $object, $modulepart) if multidir_output not defined. * Old usage: '015' with level 3->"0/1/5/", '015' with level 1->"5/", 'ABC-1' with level 3 ->"0/0/1/" * * @param string $num Id of object (deprecated, $object will be used in future) diff --git a/htdocs/core/modules/modResource.class.php b/htdocs/core/modules/modResource.class.php index f6674bdcfd741c2fdab9ddef841e02f30da6f902..020fa92e9f366cc4609f438d3c9d545aa6b71b1f 100644 --- a/htdocs/core/modules/modResource.class.php +++ b/htdocs/core/modules/modResource.class.php @@ -305,7 +305,7 @@ class modResource extends DolibarrModules ); //$this->import_convertvalue_array[$r]=array('s.fk_soc'=>array('rule'=>'lastrowid',table='t'); $this->import_regex_array[$r]=array('s.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?$'); - $this->import_examplevalues_array[$r]=array('r.ref'=>"REF1",'r.fk_code_type_resource'=>"Code from dictionnary resource type",'r.datec'=>"2017-01-01 or 2017-01-01 12:30:00"); + $this->import_examplevalues_array[$r]=array('r.ref'=>"REF1",'r.fk_code_type_resource'=>"Code from dictionary resource type",'r.datec'=>"2017-01-01 or 2017-01-01 12:30:00"); $this->import_updatekeys_array[$r]=array('r.rf'=>'ResourceFormLabel_ref'); } diff --git a/htdocs/install/mysql/migration/4.0.0-5.0.0.sql b/htdocs/install/mysql/migration/4.0.0-5.0.0.sql index 7eb086126115ff72d0d632979dbdcad13ab3f26a..a750581ae49abcc91d135cc10a885bc684b8342c 100644 --- a/htdocs/install/mysql/migration/4.0.0-5.0.0.sql +++ b/htdocs/install/mysql/migration/4.0.0-5.0.0.sql @@ -218,7 +218,7 @@ create table llx_user_employment tms timestamp, fk_user_creat integer, fk_user_modif integer, - job varchar(128), -- job position. may be a dictionnary + job varchar(128), -- job position. may be a dictionary status integer NOT NULL, -- draft, active, closed salary double(24,8), -- last and current value stored into llx_user salaryextra double(24,8), -- last and current value stored into llx_user diff --git a/htdocs/install/mysql/tables/llx_user_employment.sql b/htdocs/install/mysql/tables/llx_user_employment.sql index 4dfa2548c2fbea70e5a526aacd72dde9498efb22..80520ce3dd87f6740aee8458411fea616677f114 100644 --- a/htdocs/install/mysql/tables/llx_user_employment.sql +++ b/htdocs/install/mysql/tables/llx_user_employment.sql @@ -28,7 +28,7 @@ create table llx_user_employment tms timestamp, fk_user_creat integer, fk_user_modif integer, - job varchar(128), -- job position. may be a dictionnary + job varchar(128), -- job position. may be a dictionary status integer NOT NULL, -- draft, active, closed salary double(24,8), -- last and current value stored into llx_user salaryextra double(24,8), -- last and current value stored into llx_user diff --git a/htdocs/variants/generator.php b/htdocs/variants/generator.php index 7b0358fd1762d154b82e8562ae071ab2e5ec0a2c..d41628998746565e9ed274f4c34afd417b152bff 100644 --- a/htdocs/variants/generator.php +++ b/htdocs/variants/generator.php @@ -162,19 +162,19 @@ if (! empty($id) || ! empty($ref)) { print_fiche_titre($langs->trans('ProductCombinationGenerator')); - $dictionnary_attr = array(); + $dictionary_attr = array(); foreach ($prodattr->fetchAll() as $attr) { - $dictionnary_attr[$attr->id] = $attr; + $dictionary_attr[$attr->id] = $attr; foreach ($prodattrval->fetchAllByProductAttribute($attr->id) as $attrval) { - $dictionnary_attr[$attr->id]->values[$attrval->id] = $attrval; + $dictionary_attr[$attr->id]->values[$attrval->id] = $attrval; } } ?> <script> - dictionnary_attr = <?php echo json_encode($dictionnary_attr) ?>; + dictionary_attr = <?php echo json_encode($dictionary_attr) ?>; weight_units = '<?php echo measuring_units_string($object->weight_units, 'weight') ?>'; attr_selected = {}; percentage_variation = jQuery('input#price_var_percent').prop('checked'); @@ -191,7 +191,7 @@ if (! empty($id) || ! empty($ref)) { if (!attr_selected.hasOwnProperty(attr)) { - var label = dictionnary_attr[attr].label; + var label = dictionary_attr[attr].label; var table = jQuery(document.createElement('table')) .attr('id', 'combinations_'+attr) @@ -239,7 +239,7 @@ if (! empty($id) || ! empty($ref)) { } html.append( - jQuery(document.createElement('td')).text(dictionnary_attr[attr].values[val].value), + jQuery(document.createElement('td')).text(dictionary_attr[attr].values[val].value), jQuery(document.createElement('td')).css('text-align', 'center').append( jQuery(document.createElement('input')).attr('type', 'text').css('width', '50px').attr('name', 'combinations[' + attr + '][' + val + '][price]').val(price), percent_symbol_html @@ -350,7 +350,7 @@ if (! empty($id) || ! empty($ref)) { <div style="float:left; width: 20%"> <select id="features" multiple style="width: 100%; height: 300px; overflow: auto"> - <?php foreach ($dictionnary_attr as $attr): ?> + <?php foreach ($dictionary_attr as $attr): ?> <optgroup label="<?php echo $attr->label ?>"> <?php foreach ($attr->values as $attrval): ?> <option value="<?php echo $attr->id.':'.$attrval->id ?>"<?php diff --git a/test/phpunit/RestAPIDocumentTest.php b/test/phpunit/RestAPIDocumentTest.php index ea0c218027fc35490650b1a8b23afc3043b5e4bc..0ff33bc36c55c10763d6ec33157d9705ab9adccd 100644 --- a/test/phpunit/RestAPIDocumentTest.php +++ b/test/phpunit/RestAPIDocumentTest.php @@ -131,11 +131,11 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase } /** - * testRestReceiveDocument. + * testPushDocument. * * @return int */ - public function testRestReceiveDocument() + public function testPushDocument() { global $conf,$user,$langs,$db; @@ -143,20 +143,17 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase $fileName = 'img250x20.png'; $filePath = dirname(__FILE__).'/'.$fileName; - $mimetype = mime_content_type($filePath); - // Init Curl file object - // See https://wiki.php.net/rfc/curl-file-upload - $cfile = curl_file_create($filePath, $mimetype); + $mimetype = dol_mimetype($filePath); echo __METHOD__.' Request POST url='.$url."\n"; - // Send to existant directory - $data = array( + // Send to existant directory + $data = array( 'modulepart' => 'facture', - 'file' => $cfile, + 'file' => 'eeeeeee', 'refname' => 'AV1303-0003', 'name' => $fileName, // Name for destination - 'type' => $mimetype, ); + 'mime' => $mimetype ); $result = getURLContent($url, 'POST', $data, 1); @@ -165,8 +162,8 @@ class RestAPIDocumentTest extends PHPUnit_Framework_TestCase $this->assertEquals($result['curl_error_no'], ''); $this->assertEquals($result['content'], 'true'); - // Send to unexistant directory - $data = array( + // Send to unexistant directory + $data = array( 'modulepart' => 'facture', 'file' => $cfile, 'name' => 'AV1303-0003STSEIUDEISRESIJLEU/'.$fileName, // Name for destination