dolibarr 18.0.7
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.'/core/lib/files.lib.php';
27
35{
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, $langs;
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 = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 0 : 1;
186 $hidedesc = empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 0 : 1;
187 $hideref = empty($conf->global->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 $this->invoice = new Facture($this->db);
194 $result = $this->invoice->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
195 if (!$result) {
196 throw new RestException(404, 'Invoice not found');
197 }
198
199 $templateused = $doctemplate ? $doctemplate : $this->invoice->model_pdf;
200 $result = $this->invoice->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 $this->supplier_invoice = new FactureFournisseur($this->db);
207 $result = $this->supplier_invoice->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 : $this->supplier_invoice->model_pdf;
213 $result = $this->supplier_invoice->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 $this->order = new Commande($this->db);
220 $result = $this->order->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
221 if (!$result) {
222 throw new RestException(404, 'Order not found');
223 }
224 $templateused = $doctemplate ? $doctemplate : $this->order->model_pdf;
225 $result = $this->order->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 $this->propal = new Propal($this->db);
232 $result = $this->propal->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
233 if (!$result) {
234 throw new RestException(404, 'Proposal not found');
235 }
236 $templateused = $doctemplate ? $doctemplate : $this->propal->model_pdf;
237 $result = $this->propal->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 $this->contract = new Contrat($this->db);
245 $result = $this->contract->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 : $this->contract->model_pdf;
252 $result = $this->contract->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
253
254 if ($result <= 0) {
255 throw new RestException(500, 'Error generating document missing doctemplate parameter');
256 }
257 } else {
258 throw new RestException(403, 'Generation not available for this modulepart');
259 }
260
261 $filename = basename($original_file);
262 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
263
264 if (!file_exists($original_file_osencoded)) {
265 throw new RestException(404, 'File not found');
266 }
267
268 $file_content = file_get_contents($original_file_osencoded);
269 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');
270 }
271
291 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
292 {
293 global $conf;
294
295 if (empty($modulepart)) {
296 throw new RestException(400, 'bad value for parameter modulepart');
297 }
298
299 if (empty($id) && empty($ref)) {
300 throw new RestException(400, 'bad value for parameter id or ref');
301 }
302
303 $id = (empty($id) ? 0 : $id);
304 $recursive = 0;
305 $type = 'files';
306
307 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
308 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
309
310 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
311 throw new RestException(401);
312 }
313
314 $object = new Societe($this->db);
315 $result = $object->fetch($id, $ref);
316 if (!$result) {
317 throw new RestException(404, 'Thirdparty not found');
318 }
319
320 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
321 } elseif ($modulepart == 'user') {
322 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
323
324 // Can get doc if has permission to read all user or if it is user itself
325 if (!DolibarrApiAccess::$user->rights->user->user->lire && DolibarrApiAccess::$user->id != $id) {
326 throw new RestException(401);
327 }
328
329 $object = new User($this->db);
330 $result = $object->fetch($id, $ref);
331 if (!$result) {
332 throw new RestException(404, 'User not found');
333 }
334
335 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
336 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
337 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
338
339 if (!DolibarrApiAccess::$user->rights->adherent->lire) {
340 throw new RestException(401);
341 }
342
343 $object = new Adherent($this->db);
344 $result = $object->fetch($id, $ref);
345 if (!$result) {
346 throw new RestException(404, 'Member not found');
347 }
348
349 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
350 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
351 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
352
353 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
354 throw new RestException(401);
355 }
356
357 $object = new Propal($this->db);
358 $result = $object->fetch($id, $ref);
359 if (!$result) {
360 throw new RestException(404, 'Proposal not found');
361 }
362
363 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
364 } elseif ($modulepart == 'supplier_proposal') {
365 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
366
367 if (!DolibarrApiAccess::$user->rights->supplier_proposal->read) {
368 throw new RestException(401);
369 }
370
371 $object = new Propal($this->db);
372 $result = $object->fetch($id, $ref);
373 if (!$result) {
374 throw new RestException(404, 'Supplier proposal not found');
375 }
376
377 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
378 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
379 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
380
381 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
382 throw new RestException(401);
383 }
384
385 $object = new Commande($this->db);
386 $result = $object->fetch($id, $ref);
387 if (!$result) {
388 throw new RestException(404, 'Order not found');
389 }
390
391 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
392 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
393 $modulepart = 'supplier_order';
394
395 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
396
397 if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->lire) && empty(DolibarrApiAccess::$user->rights->supplier_order->lire)) {
398 throw new RestException(401);
399 }
400
401 $object = new CommandeFournisseur($this->db);
402 $result = $object->fetch($id, $ref);
403 if (!$result) {
404 throw new RestException(404, 'Purchase order not found');
405 }
406
407 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
408 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
409 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
410
411 if (!DolibarrApiAccess::$user->rights->expedition->lire) {
412 throw new RestException(401);
413 }
414
415 $object = new Expedition($this->db);
416 $result = $object->fetch($id, $ref);
417 if (!$result) {
418 throw new RestException(404, 'Shipment not found');
419 }
420
421 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
422 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
423 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
424
425 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
426 throw new RestException(401);
427 }
428
429 $object = new Facture($this->db);
430 $result = $object->fetch($id, $ref);
431 if (!$result) {
432 throw new RestException(404, 'Invoice not found');
433 }
434
435 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
436 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
437 $modulepart = 'supplier_invoice';
438
439 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
440
441 if (empty(DolibarrApiAccess::$user->rights->fournisseur->facture->lire) && empty(DolibarrApiAccess::$user->rights->supplier_invoice->lire)) {
442 throw new RestException(401);
443 }
444
445 $object = new FactureFournisseur($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->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
452 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
453 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
454
455 if (!DolibarrApiAccess::$user->rights->produit->lire) {
456 throw new RestException(401);
457 }
458
459 $object = new Product($this->db);
460 $result = $object->fetch($id, $ref);
461 if ($result == 0) {
462 throw new RestException(404, 'Product not found');
463 } elseif ($result < 0) {
464 throw new RestException(500, 'Error while fetching object: '.$object->error);
465 }
466
467 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
468 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
469 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
470
471 if (!DolibarrApiAccess::$user->rights->agenda->myactions->read && !DolibarrApiAccess::$user->rights->agenda->allactions->read) {
472 throw new RestException(401);
473 }
474
475 $object = new ActionComm($this->db);
476 $result = $object->fetch($id, $ref);
477 if (!$result) {
478 throw new RestException(404, 'Event not found');
479 }
480
481 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
482 } elseif ($modulepart == 'expensereport') {
483 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
484
485 if (!DolibarrApiAccess::$user->rights->expensereport->lire) {
486 throw new RestException(401);
487 }
488
489 $object = new ExpenseReport($this->db);
490 $result = $object->fetch($id, $ref);
491 if (!$result) {
492 throw new RestException(404, 'Expense report not found');
493 }
494
495 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
496 } elseif ($modulepart == 'knowledgemanagement') {
497 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
498
499 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
500 throw new RestException(401);
501 }
502
503 $object = new KnowledgeRecord($this->db);
504 $result = $object->fetch($id, $ref);
505 if (!$result) {
506 throw new RestException(404, 'KM article not found');
507 }
508
509 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
510 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
511 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
512
513 if (!DolibarrApiAccess::$user->rights->categorie->lire) {
514 throw new RestException(401);
515 }
516
517 $object = new Categorie($this->db);
518 $result = $object->fetch($id, $ref);
519 if (!$result) {
520 throw new RestException(404, 'Category not found');
521 }
522
523 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
524 } elseif ($modulepart == 'ecm') {
525 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
526 // // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
527
528 // if (!DolibarrApiAccess::$user->rights->ecm->read) {
529 // throw new RestException(401);
530 // }
531
532 // // $object = new EcmDirectory($this->db);
533 // // $result = $object->fetch($ref);
534 // // if (!$result) {
535 // // throw new RestException(404, 'EcmDirectory not found');
536 // // }
537 // $upload_dir = $conf->ecm->dir_output;
538 // $type = 'all';
539 // $recursive = 0;
540 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
541 $modulepart = 'contrat';
542 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
543
544 $object = new Contrat($this->db);
545 $result = $object->fetch($id, $ref);
546 if (!$result) {
547 throw new RestException(404, 'Contract not found');
548 }
549
550 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
551 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
552 $modulepart = 'project';
553 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
554
555 $object = new Project($this->db);
556 $result = $object->fetch($id, $ref);
557 if (!$result) {
558 throw new RestException(404, 'Project not found');
559 }
560
561 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
562 } else {
563 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
564 }
565
566 $objectType = $modulepart;
567 if (! empty($object->id) && ! empty($object->table_element)) {
568 $objectType = $object->table_element;
569 }
570
571 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
572 if (empty($filearray)) {
573 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
574 } else {
575 if (($object->id) > 0 && !empty($modulepart)) {
576 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
577 $ecmfile = new EcmFiles($this->db);
578 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
579 if ($result < 0) {
580 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
581 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
582 $count = count($filearray);
583 for ($i = 0 ; $i < $count ; $i++) {
584 foreach ($ecmfile->lines as $line) {
585 if ($filearray[$i]['name'] == $line->filename) {
586 $filearray[$i] = array_merge($filearray[$i], (array) $line);
587 }
588 }
589 }
590 }
591 }
592 }
593
594 return $filearray;
595 }
596
597
606 /*
607 public function get($id) {
608 return array('note'=>'xxx');
609 }*/
610
611
638 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
639 {
640 global $db, $conf;
641
642 //var_dump($modulepart);
643 //var_dump($filename);
644 //var_dump($filecontent);exit;
645
646 $modulepartorig = $modulepart;
647
648 if (empty($modulepart)) {
649 throw new RestException(400, 'Modulepart not provided.');
650 }
651
652 if (!DolibarrApiAccess::$user->rights->ecm->upload) {
653 throw new RestException(401);
654 }
655
656 $newfilecontent = '';
657 if (empty($fileencoding)) {
658 $newfilecontent = $filecontent;
659 }
660 if ($fileencoding == 'base64') {
661 $newfilecontent = base64_decode($filecontent);
662 }
663
664 $original_file = dol_sanitizeFileName($filename);
665
666 // Define $uploadir
667 $object = null;
668 $entity = DolibarrApiAccess::$user->entity;
669 if (empty($entity)) {
670 $entity = 1;
671 }
672
673 if ($ref) {
674 $tmpreldir = '';
675 $fetchbyid = false;
676
677 if ($modulepart == 'facture' || $modulepart == 'invoice') {
678 $modulepart = 'facture';
679
680 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
681 $object = new Facture($this->db);
682 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
683 $modulepart = 'supplier_invoice';
684
685 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
686 $object = new FactureFournisseur($this->db);
687 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
688 $modulepart = 'commande';
689
690 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
691 $object = new Commande($this->db);
692 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
693 $modulepart = 'supplier_order';
694
695 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
696 $object = new CommandeFournisseur($this->db);
697 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
698 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
699 $object = new Project($this->db);
700 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
701 $modulepart = 'project_task';
702
703 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
704 $object = new Task($this->db);
705
706 $task_result = $object->fetch('', $ref);
707
708 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
709 if ($task_result > 0) {
710 $project_result = $object->fetch_projet();
711
712 if ($project_result >= 0) {
713 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
714 }
715 } else {
716 throw new RestException(500, 'Error while fetching Task '.$ref);
717 }
718 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
719 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
720 $object = new Product($this->db);
721 } elseif ($modulepart == 'expensereport') {
722 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
723 $object = new ExpenseReport($this->db);
724 } elseif ($modulepart == 'fichinter') {
725 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
726 $object = new Fichinter($this->db);
727 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
728 $modulepart = 'adherent';
729 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
730 $object = new Adherent($this->db);
731 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
732 $modulepart = 'propale';
733 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
734 $object = new Propal($this->db);
735 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
736 $modulepart = 'agenda';
737 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
738 $object = new ActionComm($this->db);
739 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
740 $modulepart = 'contact';
741 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
742 $object = new Contact($this->db);
743 $fetchbyid = true;
744 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
745 $modulepart = 'contrat';
746 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
747 $object = new Contrat($this->db);
748 } else {
749 // TODO Implement additional moduleparts
750 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
751 }
752
753 if (is_object($object)) {
754 if ($fetchbyid) {
755 $result = $object->fetch($ref);
756 } else {
757 $result = $object->fetch('', $ref);
758 }
759
760 if ($result == 0) {
761 throw new RestException(404, "Object with ref '".$ref."' was not found.");
762 } elseif ($result < 0) {
763 throw new RestException(500, 'Error while fetching object: '.$object->error);
764 }
765 }
766
767 if (!($object->id > 0)) {
768 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
769 }
770
771 // Special cases that need to use get_exdir to get real dir of object
772 // In future, all object should use this to define path of documents.
773 if ($modulepart == 'supplier_invoice') {
774 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
775 }
776
777 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
778
779 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
780 $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
781
782 if (empty($upload_dir) || $upload_dir == '/') {
783 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.');
784 }
785 } else {
786 if ($modulepart == 'invoice') {
787 $modulepart = 'facture';
788 }
789 if ($modulepart == 'member') {
790 $modulepart = 'adherent';
791 }
792
793 $relativefile = $subdir;
794 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
795 $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
796
797 if (empty($upload_dir) || $upload_dir == '/') {
798 if (!empty($tmp['error'])) {
799 throw new RestException(401, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
800 } else {
801 throw new RestException(500, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
802 }
803 }
804 }
805 // $original_file here is still value of filename without any dir.
806
807 $upload_dir = dol_sanitizePathName($upload_dir);
808
809 if (!empty($createdirifnotexists)) {
810 if (dol_mkdir($upload_dir) < 0) { // needed by products
811 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
812 }
813 }
814
815 $destfile = $upload_dir.'/'.$original_file;
816 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
817 dol_delete_file($destfiletmp);
818 //var_dump($original_file);exit;
819
820 if (!dol_is_dir(dirname($destfile))) {
821 throw new RestException(401, 'Directory not exists : '.dirname($destfile));
822 }
823
824 if (!$overwriteifexists && dol_is_file($destfile)) {
825 throw new RestException(500, "File with name '".$original_file."' already exists.");
826 }
827
828 // in case temporary directory admin/temp doesn't exist
829 if (!dol_is_dir(dirname($destfiletmp))) {
830 dol_mkdir(dirname($destfiletmp));
831 }
832
833 $fhandle = @fopen($destfiletmp, 'w');
834 if ($fhandle) {
835 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
836 fclose($fhandle);
837 dolChmod($destfiletmp);
838 } else {
839 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
840 }
841
842 $disablevirusscan = 0;
843 $src_file = $destfiletmp;
844 $dest_file = $destfile;
845
846 // Security:
847 // If we need to make a virus scan
848 if (empty($disablevirusscan) && file_exists($src_file)) {
849 $checkvirusarray = dolCheckVirus($src_file);
850 if (count($checkvirusarray)) {
851 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING);
852 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray));
853 }
854 }
855
856 // Security:
857 // Disallow file with some extensions. We rename them.
858 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
859 if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) {
860 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
861 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
862 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
863 $publicmediasdirwithslash .= '/';
864 }
865
866 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
867 $dest_file .= '.noexe';
868 }
869 }
870
871 // Security:
872 // We refuse cache files/dirs, upload using .. and pipes into filenames.
873 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
874 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
875 throw new RestException(500, "Refused to deliver file ".$src_file);
876 }
877
878 // Security:
879 // We refuse cache files/dirs, upload using .. and pipes into filenames.
880 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
881 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
882 throw new RestException(500, "Refused to deliver file ".$dest_file);
883 }
884
885 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
886 if (!empty($object) && is_object($object) && $object->id > 0) {
887 $moreinfo['src_object_type'] = $object->table_element;
888 $moreinfo['src_object_id'] = $object->id;
889 }
890
891 // Move the temporary file at its final emplacement
892 $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
893 if (!$result) {
894 throw new RestException(500, "Failed to move file into '".$dest_file."'");
895 }
896
897 return dol_basename($destfile);
898 }
899
913 public function delete($modulepart, $original_file)
914 {
915 global $conf, $langs;
916
917 if (empty($modulepart)) {
918 throw new RestException(400, 'bad value for parameter modulepart');
919 }
920 if (empty($original_file)) {
921 throw new RestException(400, 'bad value for parameter original_file');
922 }
923
924 //--- Finds and returns the document
925 $entity = $conf->entity;
926
927 // Special cases that need to use get_exdir to get real dir of object
928 // If future, all object should use this to define path of documents.
929 /*
930 $tmpreldir = '';
931 if ($modulepart == 'supplier_invoice') {
932 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
933 }
934
935 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
936 $relativefile = $original_file;
937
938 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
939 $accessallowed = $check_access['accessallowed'];
940 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
941 $original_file = $check_access['original_file'];
942
943 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
944 throw new RestException(401);
945 }
946 if (!$accessallowed) {
947 throw new RestException(401);
948 }
949
950 $filename = basename($original_file);
951 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
952
953 if (!file_exists($original_file_osencoded)) {
954 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
955 throw new RestException(404, 'File not found');
956 }
957
958 if (@unlink($original_file_osencoded)) {
959 return array(
960 'success' => array(
961 'code' => 200,
962 'message' => 'Document deleted'
963 )
964 );
965 }
966
967 throw new RestException(401);
968 }
969
970 // phpcs:disable PEAR.NamingConventions.ValidFunctionName
978 private function _validate_file($data)
979 {
980 // phpcs:enable
981 $result = array();
982 foreach (Documents::$DOCUMENT_FIELDS as $field) {
983 if (!isset($data[$field])) {
984 throw new RestException(400, "$field field missing");
985 }
986 $result[$field] = $data[$field];
987 }
988 return $result;
989 }
990}
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 contact/addresses.
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 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.
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)