dolibarr 19.0.4
api_documents.class.php
1<?php
2/* Copyright (C) 2016 Xebax Christy <xebax@wanadoo.fr>
3 * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2016 Jean-François Ferry <jfefe@aternatik.fr>
5 * Copyright (C) 2023 Romain Neil <contact@romain-neil.fr>
6 * Copyright (C) 2025 William Mead <william@m34d.com>
7 *
8 * This program is free software you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22use Luracast\Restler\RestException;
23use Luracast\Restler\Format\UploadFormat;
24
25require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
26require_once DOL_DOCUMENT_ROOT.'/api/class/api.class.php';
27require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
28
36{
40 public static $DOCUMENT_FIELDS = array(
41 'modulepart'
42 );
43
47 public function __construct()
48 {
49 global $db;
50 $this->db = $db;
51 }
52
53
70 public function index($modulepart, $original_file = '')
71 {
72 global $conf;
73
74 if (empty($modulepart)) {
75 throw new RestException(400, 'bad value for parameter modulepart');
76 }
77 if (empty($original_file)) {
78 throw new RestException(400, 'bad value for parameter original_file');
79 }
80
81 //--- Finds and returns the document
82 $entity = $conf->entity;
83
84 // Special cases that need to use get_exdir to get real dir of object
85 // If future, all object should use this to define path of documents.
86 /*
87 $tmpreldir = '';
88 if ($modulepart == 'supplier_invoice') {
89 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
90 }
91
92 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
93 $relativefile = $original_file;
94
95 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
96 $accessallowed = $check_access['accessallowed'];
97 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
98 $original_file = $check_access['original_file'];
99
100 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
101 throw new RestException(401);
102 }
103 if (!$accessallowed) {
104 throw new RestException(401);
105 }
106
107 $filename = basename($original_file);
108 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
109
110 if (!file_exists($original_file_osencoded)) {
111 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
112 throw new RestException(404, 'File not found');
113 }
114
115 $file_content = file_get_contents($original_file_osencoded);
116 return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'encoding'=>'base64');
117 }
118
119
141 public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
142 {
143 global $conf, $langs;
144
145 if (empty($modulepart)) {
146 throw new RestException(400, 'bad value for parameter modulepart');
147 }
148 if (empty($original_file)) {
149 throw new RestException(400, 'bad value for parameter original_file');
150 }
151
152 $outputlangs = $langs;
153 if ($langcode && $langs->defaultlang != $langcode) {
154 $outputlangs = new Translate('', $conf);
155 $outputlangs->setDefaultLang($langcode);
156 }
157
158 //--- Finds and returns the document
159 $entity = $conf->entity;
160
161 // Special cases that need to use get_exdir to get real dir of object
162 // If future, all object should use this to define path of documents.
163 /*
164 $tmpreldir = '';
165 if ($modulepart == 'supplier_invoice') {
166 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
167 }
168
169 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
170 $relativefile = $original_file;
171
172 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
173 $accessallowed = $check_access['accessallowed'];
174 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
175 $original_file = $check_access['original_file'];
176
177 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
178 throw new RestException(401);
179 }
180 if (!$accessallowed) {
181 throw new RestException(401);
182 }
183
184 // --- Generates the document
185 $hidedetails = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1;
186 $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1;
187 $hideref = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 0 : 1;
188
189 $templateused = '';
190
191 if ($modulepart == 'facture' || $modulepart == 'invoice') {
192 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
193 $tmpobject = new Facture($this->db);
194 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
195 if (!$result) {
196 throw new RestException(404, 'Invoice not found');
197 }
198
199 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
200 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
201 if ($result <= 0) {
202 throw new RestException(500, 'Error generating document');
203 }
204 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
205 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
206 $tmpobject = new FactureFournisseur($this->db);
207 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
208 if (!$result) {
209 throw new RestException(404, 'Supplier invoice not found');
210 }
211
212 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
213 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
214 if ($result < 0) {
215 throw new RestException(500, 'Error generating document');
216 }
217 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
218 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
219 $tmpobject = new Commande($this->db);
220 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
221 if (!$result) {
222 throw new RestException(404, 'Order not found');
223 }
224 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
225 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
226 if ($result <= 0) {
227 throw new RestException(500, 'Error generating document');
228 }
229 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
230 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
231 $tmpobject = new Propal($this->db);
232 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
233 if (!$result) {
234 throw new RestException(404, 'Proposal not found');
235 }
236 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
237 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
238 if ($result <= 0) {
239 throw new RestException(500, 'Error generating document');
240 }
241 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
242 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
243
244 $tmpobject = new Contrat($this->db);
245 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
246
247 if (!$result) {
248 throw new RestException(404, 'Contract not found');
249 }
250
251 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
252 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
253
254 if ($result <= 0) {
255 throw new RestException(500, 'Error generating document missing doctemplate parameter');
256 }
257 } elseif ($modulepart == 'expedition' || $modulepart == 'shipment') {
258 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
259
260 $tmpobject = new Expedition($this->db);
261 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
262
263 if (!$result) {
264 throw new RestException(404, 'Shipment not found');
265 }
266
267 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
268 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
269
270 if ($result <= 0) {
271 throw new RestException(500, 'Error generating document missing doctemplate parameter');
272 }
273 } else {
274 throw new RestException(403, 'Generation not available for this modulepart');
275 }
276
277 $filename = basename($original_file);
278 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
279
280 if (!file_exists($original_file_osencoded)) {
281 throw new RestException(404, 'File not found');
282 }
283
284 $file_content = file_get_contents($original_file_osencoded);
285 return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'langcode'=>$outputlangs->defaultlang, 'template'=>$templateused, 'encoding'=>'base64');
286 }
287
307 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
308 {
309 global $conf;
310
311 if (empty($modulepart)) {
312 throw new RestException(400, 'bad value for parameter modulepart');
313 }
314
315 if (empty($id) && empty($ref)) {
316 throw new RestException(400, 'bad value for parameter id or ref');
317 }
318
319 $id = (empty($id) ? 0 : $id);
320 $recursive = 0;
321 $type = 'files';
322
323 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
324 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
325
326 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
327 throw new RestException(401);
328 }
329
330 $object = new Societe($this->db);
331 $result = $object->fetch($id, $ref);
332 if (!$result) {
333 throw new RestException(404, 'Thirdparty not found');
334 }
335
336 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
337 } elseif ($modulepart == 'user') {
338 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
339
340 // Can get doc if has permission to read all user or if it is user itself
341 if (!DolibarrApiAccess::$user->rights->user->user->lire && DolibarrApiAccess::$user->id != $id) {
342 throw new RestException(401);
343 }
344
345 $object = new User($this->db);
346 $result = $object->fetch($id, $ref);
347 if (!$result) {
348 throw new RestException(404, 'User not found');
349 }
350
351 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
352 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
353 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
354
355 if (!DolibarrApiAccess::$user->rights->adherent->lire) {
356 throw new RestException(401);
357 }
358
359 $object = new Adherent($this->db);
360 $result = $object->fetch($id, $ref);
361 if (!$result) {
362 throw new RestException(404, 'Member not found');
363 }
364
365 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
366 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
367 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
368
369 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
370 throw new RestException(401);
371 }
372
373 $object = new Propal($this->db);
374 $result = $object->fetch($id, $ref);
375 if (!$result) {
376 throw new RestException(404, 'Proposal not found');
377 }
378
379 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
380 } elseif ($modulepart == 'supplier_proposal') {
381 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
382
383 if (!DolibarrApiAccess::$user->rights->supplier_proposal->read) {
384 throw new RestException(401);
385 }
386
387 $object = new Propal($this->db);
388 $result = $object->fetch($id, $ref);
389 if (!$result) {
390 throw new RestException(404, 'Supplier proposal not found');
391 }
392
393 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
394 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
395 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
396
397 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
398 throw new RestException(401);
399 }
400
401 $object = new Commande($this->db);
402 $result = $object->fetch($id, $ref);
403 if (!$result) {
404 throw new RestException(404, 'Order not found');
405 }
406
407 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
408 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
409 $modulepart = 'supplier_order';
410
411 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
412
413 if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->lire) && empty(DolibarrApiAccess::$user->rights->supplier_order->lire)) {
414 throw new RestException(401);
415 }
416
417 $object = new CommandeFournisseur($this->db);
418 $result = $object->fetch($id, $ref);
419 if (!$result) {
420 throw new RestException(404, 'Purchase order not found');
421 }
422
423 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
424 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
425 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
426
427 if (!DolibarrApiAccess::$user->rights->expedition->lire) {
428 throw new RestException(401);
429 }
430
431 $object = new Expedition($this->db);
432 $result = $object->fetch($id, $ref);
433 if (!$result) {
434 throw new RestException(404, 'Shipment not found');
435 }
436
437 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
438 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
439 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
440
441 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
442 throw new RestException(401);
443 }
444
445 $object = new Facture($this->db);
446 $result = $object->fetch($id, $ref);
447 if (!$result) {
448 throw new RestException(404, 'Invoice not found');
449 }
450
451 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
452 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
453 $modulepart = 'supplier_invoice';
454
455 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
456
457 if (empty(DolibarrApiAccess::$user->rights->fournisseur->facture->lire) && empty(DolibarrApiAccess::$user->rights->supplier_invoice->lire)) {
458 throw new RestException(401);
459 }
460
461 $object = new FactureFournisseur($this->db);
462 $result = $object->fetch($id, $ref);
463 if (!$result) {
464 throw new RestException(404, 'Invoice not found');
465 }
466
467 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
468 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
469 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
470
471 if (!DolibarrApiAccess::$user->rights->produit->lire) {
472 throw new RestException(401);
473 }
474
475 $object = new Product($this->db);
476 $result = $object->fetch($id, $ref);
477 if ($result == 0) {
478 throw new RestException(404, 'Product not found');
479 } elseif ($result < 0) {
480 throw new RestException(500, 'Error while fetching object: '.$object->error);
481 }
482
483 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
484 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
485 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
486
487 if (!DolibarrApiAccess::$user->rights->agenda->myactions->read && !DolibarrApiAccess::$user->rights->agenda->allactions->read) {
488 throw new RestException(401);
489 }
490
491 $object = new ActionComm($this->db);
492 $result = $object->fetch($id, $ref);
493 if (!$result) {
494 throw new RestException(404, 'Event not found');
495 }
496
497 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
498 } elseif ($modulepart == 'expensereport') {
499 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
500
501 if (!DolibarrApiAccess::$user->rights->expensereport->lire) {
502 throw new RestException(401);
503 }
504
505 $object = new ExpenseReport($this->db);
506 $result = $object->fetch($id, $ref);
507 if (!$result) {
508 throw new RestException(404, 'Expense report not found');
509 }
510
511 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
512 } elseif ($modulepart == 'knowledgemanagement') {
513 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
514
515 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
516 throw new RestException(401);
517 }
518
519 $object = new KnowledgeRecord($this->db);
520 $result = $object->fetch($id, $ref);
521 if (!$result) {
522 throw new RestException(404, 'KM article not found');
523 }
524
525 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
526 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
527 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
528
529 if (!DolibarrApiAccess::$user->rights->categorie->lire) {
530 throw new RestException(401);
531 }
532
533 $object = new Categorie($this->db);
534 $result = $object->fetch($id, $ref);
535 if (!$result) {
536 throw new RestException(404, 'Category not found');
537 }
538
539 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
540 } elseif ($modulepart == 'ecm') {
541 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
542 // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
543
544 // if (!DolibarrApiAccess::$user->rights->ecm->read) {
545 // throw new RestException(401);
546 // }
547
548 // // $object = new EcmDirectory($this->db);
549 // // $result = $object->fetch($ref);
550 // // if (!$result) {
551 // // throw new RestException(404, 'EcmDirectory not found');
552 // // }
553 // $upload_dir = $conf->ecm->dir_output;
554 // $type = 'all';
555 // $recursive = 0;
556 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
557 $modulepart = 'contrat';
558 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
559
560 $object = new Contrat($this->db);
561 $result = $object->fetch($id, $ref);
562 if (!$result) {
563 throw new RestException(404, 'Contract not found');
564 }
565
566 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
567 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
568 $modulepart = 'project';
569 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
570
571 $object = new Project($this->db);
572 $result = $object->fetch($id, $ref);
573 if (!$result) {
574 throw new RestException(404, 'Project not found');
575 }
576
577 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
578 } else {
579 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
580 }
581
582 $objectType = $modulepart;
583 if (! empty($object->id) && ! empty($object->table_element)) {
584 $objectType = $object->table_element;
585 }
586
587 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
588 if (empty($filearray)) {
589 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
590 } else {
591 if (($object->id) > 0 && !empty($modulepart)) {
592 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
593 $ecmfile = new EcmFiles($this->db);
594 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
595 if ($result < 0) {
596 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
597 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
598 $count = count($filearray);
599 for ($i = 0 ; $i < $count ; $i++) {
600 foreach ($ecmfile->lines as $line) {
601 if ($filearray[$i]['name'] == $line->filename) {
602 $filearray[$i] = array_merge($filearray[$i], (array) $line);
603 }
604 }
605 }
606 }
607 }
608 }
609
610 return $filearray;
611 }
612
613
622 /*
623 public function get($id) {
624 return array('note'=>'xxx');
625 }*/
626
627
654 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
655 {
656 global $conf;
657
658 //var_dump($modulepart);
659 //var_dump($filename);
660 //var_dump($filecontent);exit;
661
662 $modulepartorig = $modulepart;
663
664 if (empty($modulepart)) {
665 throw new RestException(400, 'Modulepart not provided.');
666 }
667
668 $newfilecontent = '';
669 if (empty($fileencoding)) {
670 $newfilecontent = $filecontent;
671 }
672 if ($fileencoding == 'base64') {
673 $newfilecontent = base64_decode($filecontent);
674 }
675
676 $original_file = dol_sanitizeFileName($filename);
677
678 // Define $uploadir
679 $object = null;
680 $entity = DolibarrApiAccess::$user->entity;
681 if (empty($entity)) {
682 $entity = 1;
683 }
684
685 if ($ref) {
686 $tmpreldir = '';
687 $fetchbyid = false;
688
689 if ($modulepart == 'facture' || $modulepart == 'invoice') {
690 $modulepart = 'facture';
691
692 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
693 $object = new Facture($this->db);
694 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
695 $modulepart = 'supplier_invoice';
696
697 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
698 $object = new FactureFournisseur($this->db);
699 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
700 $modulepart = 'commande';
701
702 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
703 $object = new Commande($this->db);
704 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
705 $modulepart = 'supplier_order';
706
707 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
708 $object = new CommandeFournisseur($this->db);
709 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
710 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
711 $object = new Project($this->db);
712 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
713 $modulepart = 'project_task';
714
715 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
716 $object = new Task($this->db);
717
718 $task_result = $object->fetch('', $ref);
719
720 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
721 if ($task_result > 0) {
722 $project_result = $object->fetch_projet();
723
724 if ($project_result >= 0) {
725 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
726 }
727 } else {
728 throw new RestException(500, 'Error while fetching Task '.$ref);
729 }
730 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
731 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
732 $object = new Product($this->db);
733 } elseif ($modulepart == 'expensereport') {
734 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
735 $object = new ExpenseReport($this->db);
736 } elseif ($modulepart == 'fichinter') {
737 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
738 $object = new Fichinter($this->db);
739 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
740 $modulepart = 'adherent';
741 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
742 $object = new Adherent($this->db);
743 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
744 $modulepart = 'propale';
745 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
746 $object = new Propal($this->db);
747 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
748 $modulepart = 'agenda';
749 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
750 $object = new ActionComm($this->db);
751 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
752 $modulepart = 'contact';
753 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
754 $object = new Contact($this->db);
755 $fetchbyid = true;
756 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
757 $modulepart = 'contrat';
758 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
759 $object = new Contrat($this->db);
760 } else {
761 // TODO Implement additional moduleparts
762 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
763 }
764
765 if (is_object($object)) {
766 if ($fetchbyid) {
767 $result = $object->fetch($ref);
768 } else {
769 $result = $object->fetch('', $ref);
770 }
771
772 if ($result == 0) {
773 throw new RestException(404, "Object with ref '".$ref."' was not found.");
774 } elseif ($result < 0) {
775 throw new RestException(500, 'Error while fetching object: '.$object->error);
776 }
777 }
778
779 if (!($object->id > 0)) {
780 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
781 }
782
783 // Special cases that need to use get_exdir to get real dir of object
784 // In future, all object should use this to define path of documents.
785 if ($modulepart == 'supplier_invoice') {
786 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
787 }
788
789 // Test on permissions
790 if ($modulepart != 'ecm') {
791 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
792 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
793 $upload_dir = $tmp['original_file']; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
794 } else {
795 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
796 throw new RestException(401, 'Missing permission to upload files in ECM module');
797 }
798 $upload_dir = $conf->medias->multidir_output[$conf->entity];
799 }
800
801 if (empty($upload_dir) || $upload_dir == '/') {
802 throw new RestException(500, 'This value of modulepart ('.$modulepart.') does not support yet usage of ref. Check modulepart parameter or try to use subdir parameter instead of ref.');
803 }
804 } else {
805 if ($modulepart == 'invoice') {
806 $modulepart = 'facture';
807 }
808 if ($modulepart == 'member') {
809 $modulepart = 'adherent';
810 }
811
812 // Test on permissions
813 if ($modulepart != 'ecm') {
814 $relativefile = $subdir;
815 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
816 $upload_dir = $tmp['original_file']; // No dirname here, tmp['original_file'] is already the dir because dol_check_secure_access_document was called with param original_file that is only the dir
817 } else {
818 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
819 throw new RestException(401, 'Missing permission to upload files in ECM module');
820 }
821 $upload_dir = $conf->medias->multidir_output[$conf->entity];
822 }
823
824 if (empty($upload_dir) || $upload_dir == '/') {
825 if (!empty($tmp['error'])) {
826 throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
827 } else {
828 throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
829 }
830 }
831 }
832 // $original_file here is still value of filename without any dir.
833
834 $upload_dir = dol_sanitizePathName($upload_dir);
835
836 if (!empty($createdirifnotexists)) {
837 if (dol_mkdir($upload_dir) < 0) { // needed by products
838 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
839 }
840 }
841
842 $destfile = $upload_dir.'/'.$original_file;
843 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
844 dol_delete_file($destfiletmp);
845 //var_dump($original_file);exit;
846
847 if (!dol_is_dir(dirname($destfile))) {
848 throw new RestException(401, 'Directory not exists : '.dirname($destfile));
849 }
850
851 if (!$overwriteifexists && dol_is_file($destfile)) {
852 throw new RestException(500, "File with name '".$original_file."' already exists.");
853 }
854
855 // in case temporary directory admin/temp doesn't exist
856 if (!dol_is_dir(dirname($destfiletmp))) {
857 dol_mkdir(dirname($destfiletmp));
858 }
859
860 $fhandle = @fopen($destfiletmp, 'w');
861 if ($fhandle) {
862 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
863 fclose($fhandle);
864 dolChmod($destfiletmp);
865 } else {
866 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
867 }
868
869 $disablevirusscan = 0;
870 $src_file = $destfiletmp;
871 $dest_file = $destfile;
872
873 // Security:
874 // If we need to make a virus scan
875 if (empty($disablevirusscan) && file_exists($src_file)) {
876 $checkvirusarray = dolCheckVirus($src_file);
877 if (count($checkvirusarray)) {
878 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
879 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
880 }
881 }
882
883 // Security:
884 // Disallow file with some extensions. We rename them.
885 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
886 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
887 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
888 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
889 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
890 $publicmediasdirwithslash .= '/';
891 }
892
893 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
894 $dest_file .= '.noexe';
895 }
896 }
897
898 // Security:
899 // We refuse cache files/dirs, upload using .. and pipes into filenames.
900 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
901 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
902 throw new RestException(500, "Refused to deliver file ".$src_file);
903 }
904
905 // Security:
906 // We refuse cache files/dirs, upload using .. and pipes into filenames.
907 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
908 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
909 throw new RestException(500, "Refused to deliver file ".$dest_file);
910 }
911
912 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
913 if (!empty($object) && is_object($object) && $object->id > 0) {
914 $moreinfo['src_object_type'] = $object->table_element;
915 $moreinfo['src_object_id'] = $object->id;
916 }
917
918 // Move the temporary file at its final emplacement
919 $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
920 if (!$result) {
921 throw new RestException(500, "Failed to move file into '".$dest_file."'");
922 }
923
924 return dol_basename($destfile);
925 }
926
940 public function delete($modulepart, $original_file)
941 {
942 global $conf, $langs;
943
944 if (empty($modulepart)) {
945 throw new RestException(400, 'bad value for parameter modulepart');
946 }
947 if (empty($original_file)) {
948 throw new RestException(400, 'bad value for parameter original_file');
949 }
950
951 //--- Finds and returns the document
952 $entity = $conf->entity;
953
954 // Special cases that need to use get_exdir to get real dir of object
955 // If future, all object should use this to define path of documents.
956 /*
957 $tmpreldir = '';
958 if ($modulepart == 'supplier_invoice') {
959 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
960 }
961
962 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
963 $relativefile = $original_file;
964
965 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
966 $accessallowed = $check_access['accessallowed'];
967 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
968 $original_file = $check_access['original_file'];
969
970 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
971 throw new RestException(401);
972 }
973 if (!$accessallowed) {
974 throw new RestException(401);
975 }
976
977 $filename = basename($original_file);
978 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
979
980 if (!file_exists($original_file_osencoded)) {
981 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
982 throw new RestException(404, 'File not found');
983 }
984
985 if (@unlink($original_file_osencoded)) {
986 return array(
987 'success' => array(
988 'code' => 200,
989 'message' => 'Document deleted'
990 )
991 );
992 }
993
994 throw new RestException(401);
995 }
996
997 // phpcs:disable PEAR.NamingConventions.ValidFunctionName
1005 private function _validate_file($data)
1006 {
1007 // phpcs:enable
1008 $result = array();
1009 foreach (Documents::$DOCUMENT_FIELDS as $field) {
1010 if (!isset($data[$field])) {
1011 throw new RestException(400, "$field field missing");
1012 }
1013 $result[$field] = $data[$field];
1014 }
1015 return $result;
1016 }
1017}
Class to manage agenda events (actions)
Class to manage members of a foundation.
Class to manage categories.
Class to manage predefined suppliers products.
Class to manage customers orders.
Class to manage contracts.
API class for receive files.
post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='', $overwriteifexists=0, $createdirifnotexists=1)
Return a document.
__construct()
Constructor.
index($modulepart, $original_file='')
Download a document.
getDocumentsListByElement($modulepart, $id=0, $ref='', $sortfield='', $sortorder='')
Return the list of documents of a dedicated element (from its ID or Ref)
builddoc($modulepart, $original_file='', $doctemplate='', $langcode='')
Build a document.
_validate_file($data)
Validate fields before create or update object.
Class for API REST v1.
Definition api.class.php:32
Class to manage ECM files.
Class to manage shipments.
Class to manage Trips and Expenses.
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage interventions.
Class for KnowledgeRecord.
Class to manage products or services.
Class to manage projects.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage tasks.
Class to manage translations.
Class to manage Dolibarr users.
dolCheckVirus($src_file)
Check virus into a file.
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition files.lib.php:37
dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read')
Security check when accessing to a document (used by document.php, viewimage.php and webservices to g...
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
dol_is_dir($folder)
Test if filename is a directory.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
Contact()
Old copy.
Definition index.php:572