dolibarr 22.0.5
api_documents.class.php
1<?php
2
3/* Copyright (C) 2016 Xebax Christy <xebax@wanadoo.fr>
4 * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2016 Jean-François Ferry <jfefe@aternatik.fr>
6 * Copyright (C) 2023 Romain Neil <contact@romain-neil.fr>
7 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2025 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2025 William Mead <william@m34d.com>
10 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
11 *
12 * This program is free software you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26use Luracast\Restler\RestException;
27
28require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
29require_once DOL_DOCUMENT_ROOT.'/api/class/api.class.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
31
41{
45 public function __construct()
46 {
47 global $db;
48 $this->db = $db;
49 }
50
51
72 public function index($modulepart, $original_file = '')
73 {
74 global $conf;
75
76 if (empty($modulepart)) {
77 throw new RestException(400, 'bad value for parameter modulepart');
78 }
79 if (empty($original_file)) {
80 throw new RestException(400, 'bad value for parameter original_file');
81 }
82
83 //--- Finds and returns the document
84 $entity = $conf->entity;
85
86 // Special cases that need to use get_exdir to get real dir of object
87 // If future, all object should use this to define path of documents.
88 /*
89 $tmpreldir = '';
90 if ($modulepart == 'supplier_invoice') {
91 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
92 }
93
94 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
95 $relativefile = $original_file;
96
97 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
98 $accessallowed = $check_access['accessallowed'];
99 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
100 $original_file = $check_access['original_file'];
101
102 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
103 throw new RestException(403);
104 }
105 if (!$accessallowed) {
106 throw new RestException(403);
107 }
108
109 if (DolibarrApiAccess::$user->socid > 0) {
110 if ($sqlprotectagainstexternals) {
111 $resql = $this->db->query($sqlprotectagainstexternals);
112 if ($resql) {
113 $num = $this->db->num_rows($resql);
114 $i = 0;
115 while ($i < $num) {
116 $obj = $this->db->fetch_object($resql);
117 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
118 throw new RestException(403, 'Not allowed to download documents with such a ref');
119 }
120 $i++;
121 }
122 }
123 }
124 }
125
126 $filename = basename($original_file);
127 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
128
129 if (!file_exists($original_file_osencoded)) {
130 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
131 throw new RestException(404, 'File not found');
132 }
133
134 $file_content = file_get_contents($original_file_osencoded);
135 return array('filename' => $filename, 'content-type' => dol_mimetype($filename), 'filesize' => filesize($original_file), 'content' => base64_encode($file_content), 'encoding' => 'base64');
136 }
137
138
167 public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
168 {
169 global $conf, $langs;
170
171 if (empty($modulepart)) {
172 throw new RestException(400, 'bad value for parameter modulepart');
173 }
174 if (empty($original_file)) {
175 throw new RestException(400, 'bad value for parameter original_file');
176 }
177
178 $outputlangs = $langs;
179 if ($langcode && $langs->defaultlang != $langcode) {
180 $outputlangs = new Translate('', $conf);
181 $outputlangs->setDefaultLang($langcode);
182 }
183
184 //--- Finds and returns the document
185 $entity = $conf->entity;
186
187 // Special cases that need to use get_exdir to get real dir of object
188 // If future, all object should use this to define path of documents.
189 /*
190 $tmpreldir = '';
191 if ($modulepart == 'supplier_invoice') {
192 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
193 }
194
195 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
196 $relativefile = $original_file;
197
198 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
199 $accessallowed = $check_access['accessallowed'];
200 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
201 $original_file = $check_access['original_file'];
202
203 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
204 throw new RestException(403);
205 }
206 if (!$accessallowed) {
207 throw new RestException(403);
208 }
209
210 if (DolibarrApiAccess::$user->socid > 0) {
211 if ($sqlprotectagainstexternals) {
212 $resql = $this->db->query($sqlprotectagainstexternals);
213 if ($resql) {
214 $num = $this->db->num_rows($resql);
215 $i = 0;
216 while ($i < $num) {
217 $obj = $this->db->fetch_object($resql);
218 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
219 throw new RestException(403, 'Not allowed to download documents with such a ref');
220 }
221 $i++;
222 }
223 }
224 }
225 }
226
227 // --- Generates the document
228 $hidedetails = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1;
229 $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1;
230 $hideref = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 0 : 1;
231
232 $templateused = '';
233
234 if ($modulepart == 'facture' || $modulepart == 'invoice') {
235 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
236 $tmpobject = new Facture($this->db);
237 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
238 if (!$result) {
239 throw new RestException(404, 'Invoice not found');
240 }
241
242 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
243 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
244 if ($result <= 0) {
245 throw new RestException(500, 'Error generating document');
246 }
247 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
248 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
249 $tmpobject = new FactureFournisseur($this->db);
250 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
251 if (!$result) {
252 throw new RestException(404, 'Supplier invoice not found');
253 }
254
255 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
256 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
257 if ($result < 0) {
258 throw new RestException(500, 'Error generating document');
259 }
260 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
261 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
262 $tmpobject = new Commande($this->db);
263 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
264 if (!$result) {
265 throw new RestException(404, 'Order not found');
266 }
267 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
268 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
269 if ($result <= 0) {
270 throw new RestException(500, 'Error generating document');
271 }
272 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
273 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
274 $tmpobject = new Propal($this->db);
275 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
276 if (!$result) {
277 throw new RestException(404, 'Proposal not found');
278 }
279 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
280 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
281 if ($result <= 0) {
282 throw new RestException(500, 'Error generating document');
283 }
284 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
285 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
286
287 $tmpobject = new Contrat($this->db);
288 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
289
290 if (!$result) {
291 throw new RestException(404, 'Contract not found');
292 }
293
294 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
295 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
296
297 if ($result <= 0) {
298 throw new RestException(500, 'Error generating document missing doctemplate parameter');
299 }
300 } elseif ($modulepart == 'expedition' || $modulepart == 'shipment') {
301 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
302
303 $tmpobject = new Expedition($this->db);
304 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
305
306 if (!$result) {
307 throw new RestException(404, 'Shipment not found');
308 }
309
310 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
311 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
312
313 if ($result <= 0) {
314 throw new RestException(500, 'Error generating document missing doctemplate parameter');
315 }
316 } elseif ($modulepart == 'mrp') {
317 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
318
319 $tmpobject = new Mo($this->db);
320 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
321
322 if (!$result) {
323 throw new RestException(404, 'MO not found');
324 }
325
326 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
327 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
328
329 if ($result <= 0) {
330 throw new RestException(500, 'Error generating document missing doctemplate parameter');
331 }
332 } else {
333 throw new RestException(403, 'Generation not available for this modulepart');
334 }
335
336 $filename = basename($original_file);
337 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
338
339 if (!file_exists($original_file_osencoded)) {
340 throw new RestException(404, 'File not found');
341 }
342
343 $file_content = file_get_contents($original_file_osencoded);
344 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');
345 }
346
376 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '', $limit = 100, $page = 0, $content_type = '', $pagination_data = false)
377 {
378 global $conf;
381 if (empty($modulepart)) {
382 throw new RestException(400, 'bad value for parameter modulepart');
383 }
384
385 if (empty($id) && empty($ref)) {
386 throw new RestException(400, 'bad value for parameter id or ref');
387 }
388
389 $id = (empty($id) ? 0 : $id);
390 $recursive = 0;
391 $type = 'files';
392
393 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
394 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
395
396 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
397 throw new RestException(403);
398 }
399
400 $object = new Societe($this->db);
401 $result = $object->fetch($id, $ref);
402 if (!$result) {
403 throw new RestException(404, 'Thirdparty not found');
404 }
405
406 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
407 } elseif ($modulepart == 'user') {
408 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
409
410 // Can get doc if has permission to read all user or if it is user itself
411 if (!DolibarrApiAccess::$user->hasRight('user', 'user', 'lire') && DolibarrApiAccess::$user->id != $id) {
412 throw new RestException(403);
413 }
414
415 $object = new User($this->db);
416 $result = $object->fetch($id, $ref);
417 if (!$result) {
418 throw new RestException(404, 'User not found');
419 }
420
421 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
422 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
423 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
424
425 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
426 throw new RestException(403);
427 }
428
429 $object = new Adherent($this->db);
430 $result = $object->fetch($id, $ref);
431 if (!$result) {
432 throw new RestException(404, 'Member not found');
433 }
434
435 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
436 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
437 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
438
439 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
440 throw new RestException(403);
441 }
442
443 $object = new Propal($this->db);
444 $result = $object->fetch($id, $ref);
445 if (!$result) {
446 throw new RestException(404, 'Proposal not found');
447 }
448
449 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
450 } elseif ($modulepart == 'supplier_proposal') {
451 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
452
453 if (!DolibarrApiAccess::$user->hasRight('supplier_proposal', 'read')) {
454 throw new RestException(403);
455 }
456
457 $object = new Propal($this->db);
458 $result = $object->fetch($id, $ref);
459 if (!$result) {
460 throw new RestException(404, 'Supplier proposal not found');
461 }
462
463 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
464 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
465 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
466
467 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
468 throw new RestException(403);
469 }
470
471 $object = new Commande($this->db);
472 $result = $object->fetch($id, $ref);
473 if (!$result) {
474 throw new RestException(404, 'Order not found');
475 }
476
477 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
478 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
479 $modulepart = 'supplier_order';
480
481 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
482
483 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'commande', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_order', 'lire')) {
484 throw new RestException(403);
485 }
486
487 $object = new CommandeFournisseur($this->db);
488 $result = $object->fetch($id, $ref);
489 if (!$result) {
490 throw new RestException(404, 'Purchase order not found');
491 }
492
493 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
494 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
495 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
496
497 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
498 throw new RestException(403);
499 }
500
501 $object = new Expedition($this->db);
502 $result = $object->fetch($id, $ref);
503 if (!$result) {
504 throw new RestException(404, 'Shipment not found');
505 }
506
507 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
508 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
509 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
510
511 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
512 throw new RestException(403);
513 }
514
515 $object = new Facture($this->db);
516 $result = $object->fetch($id, $ref);
517 if (!$result) {
518 throw new RestException(404, 'Invoice not found');
519 }
520
521 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
522 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
523 $modulepart = 'supplier_invoice';
524
525 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
526
527 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'facture', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_invoice', 'lire')) {
528 throw new RestException(403);
529 }
530
531 $object = new FactureFournisseur($this->db);
532 $result = $object->fetch($id, $ref);
533 if (!$result) {
534 throw new RestException(404, 'Invoice not found');
535 }
536
537 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
538 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
539 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
540
541 if (!DolibarrApiAccess::$user->hasRight('produit', 'lire')) {
542 throw new RestException(403);
543 }
544
545 $object = new Product($this->db);
546 $result = $object->fetch($id, $ref);
547 if ($result == 0) {
548 throw new RestException(404, 'Product not found');
549 } elseif ($result < 0) {
550 throw new RestException(500, 'Error while fetching object: '.$object->error);
551 }
552
553 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
554 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
555 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
556
557 if (!DolibarrApiAccess::$user->hasRight('agenda', 'myactions', 'read') && !DolibarrApiAccess::$user->hasRight('agenda', 'allactions', 'read')) {
558 throw new RestException(403);
559 }
560
561 $object = new ActionComm($this->db);
562 $result = $object->fetch($id, $ref);
563 if (!$result) {
564 throw new RestException(404, 'Event not found');
565 }
566
567 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
568 } elseif ($modulepart == 'expensereport') {
569 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
570
571 if (!DolibarrApiAccess::$user->hasRight('expensereport', 'read')) {
572 throw new RestException(403);
573 }
574
575 $object = new ExpenseReport($this->db);
576 $result = $object->fetch($id, $ref);
577 if (!$result) {
578 throw new RestException(404, 'Expense report not found');
579 }
580
581 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
582 } elseif ($modulepart == 'knowledgemanagement') {
583 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
584
585 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
586 throw new RestException(403);
587 }
588
589 $object = new KnowledgeRecord($this->db);
590 $result = $object->fetch($id, $ref);
591 if (!$result) {
592 throw new RestException(404, 'KM article not found');
593 }
594
595 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
596 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
597 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
598
599 if (!DolibarrApiAccess::$user->hasRight('categorie', 'lire')) {
600 throw new RestException(403);
601 }
602
603 $object = new Categorie($this->db);
604 $result = $object->fetch($id, $ref);
605 if (!$result) {
606 throw new RestException(404, 'Category not found');
607 }
608
609 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
610 } elseif ($modulepart == 'ecm') {
611 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
612 // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
613
614 // if (!DolibarrApiAccess::$user->hasRight('ecm', 'read')) {
615 // throw new RestException(403);
616 // }
617
618 // // $object = new EcmDirectory($this->db);
619 // // $result = $object->fetch($ref);
620 // // if (!$result) {
621 // // throw new RestException(404, 'EcmDirectory not found');
622 // // }
623 // $upload_dir = $conf->ecm->dir_output;
624 // $type = 'all';
625 // $recursive = 0;
626 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
627 $modulepart = 'contrat';
628 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
629
630 $object = new Contrat($this->db);
631 $result = $object->fetch($id, $ref);
632 if (!$result) {
633 throw new RestException(404, 'Contract not found');
634 }
635
636 $upload_dir = $conf->contract->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
637 } elseif ($modulepart == 'intervention' || $modulepart == 'ficheinter') {
638 $modulepart = 'ficheinter';
639 require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php';
640
641 $object = new Fichinter($this->db);
642 $result = $object->fetch($id, $ref);
643 if (!$result) {
644 throw new RestException(404, 'Interventional not found');
645 }
646
647 $upload_dir = $conf->ficheinter->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'ficheinter');
648 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
649 $modulepart = 'project';
650 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
651
652 $object = new Project($this->db);
653 $result = $object->fetch($id, $ref);
654 if (!$result) {
655 throw new RestException(404, 'Project not found');
656 }
657
658 $upload_dir = $conf->project->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
659 } elseif ($modulepart == 'mrp') {
660 $modulepart = 'mrp';
661 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
662
663 $object = new Mo($this->db);
664 $result = $object->fetch($id, $ref);
665 if (!$result) {
666 throw new RestException(404, 'MO not found');
667 }
668
669 $upload_dir = $conf->mrp->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'mrp');
670 } else {
671 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
672 }
673
674 $objectType = $modulepart;
675 if (! empty($object->id) && ! empty($object->table_element)) {
676 $objectType = $object->table_element;
677 }
678
679 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
680 $countarray = count($filearray);
681 $filearray = array_slice($filearray, $limit * $page, $limit);
682 if (empty($filearray)) {
683 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
684 } else {
685 if (($object->id) > 0 && !empty($modulepart)) {
686 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
687 $ecmfile = new EcmFiles($this->db);
688 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
689 if ($result < 0) {
690 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
691 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
692 $count = count($filearray);
693 for ($i = 0 ; $i < $count ; $i++) {
694 foreach ($ecmfile->lines as $line) {
695 unset($line->db);
696 if ($filearray[$i]['name'] == $line->filename) {
697 // Next line converts EcmFilesLine properties to array
698 $filearray[$i] = array_merge($filearray[$i], (array) $line);
699 }
700 }
701 if (isset($line->filename)) $filearray[$i]['content-type'] = dol_mimetype($line->filename);
702 $arraycontenttype = explode(",", $content_type);
703 if (!empty($content_type) && isset($line->filename) && !in_array(dol_mimetype($line->filename), $arraycontenttype)) {
704 unset($filearray[$i]);
705 $countarray -= 1;
706 }
707 }
708 }
709 }
710 }
711
712 //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit)
713 if ($pagination_data) {
714 $tmp = $filearray;
715 $filearray = [];
716 $filearray['data'] = $tmp;
717 $filearray['pagination'] = [
718 'total' => (int) $countarray,
719 'page' => $page, //count starts from 0
720 'page_count' => ceil((int) $countarray / $limit),
721 'limit' => $limit
722 ];
723 }
724
725 return $filearray;
726 }
727
728
737 /*
738 public function get($id) {
739 return array('note'=>'xxx');
740 }*/
741
742
778 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1, $position = 0, $cover = '', $array_options = [], $generateThumbs = 0)
779 {
780 global $conf;
781
782 $modulepartorig = $modulepart;
783
784 if (empty($modulepart)) {
785 throw new RestException(400, 'Modulepart not provided.');
786 }
787
788 $newfilecontent = '';
789 if (empty($fileencoding)) {
790 $newfilecontent = $filecontent;
791 }
792 if ($fileencoding == 'base64') {
793 $newfilecontent = base64_decode($filecontent);
794 }
795
796 $original_file = dol_sanitizeFileName($filename);
797 $relativefile = 'UNSET';
798
799 // Define $uploadir
800 $object = null;
801 $entity = DolibarrApiAccess::$user->entity;
802 if (empty($entity)) {
803 $entity = 1;
804 }
805
806 if ($ref) {
807 $tmpreldir = '';
808 $fetchbyid = false;
809
810 if ($modulepart == 'facture' || $modulepart == 'invoice') {
811 $modulepart = 'facture';
812
813 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
814 $object = new Facture($this->db);
815 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
816 $modulepart = 'supplier_invoice';
817
818 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
819 $object = new FactureFournisseur($this->db);
820 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
821 $modulepart = 'commande';
822
823 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
824 $object = new Commande($this->db);
825 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
826 $modulepart = 'supplier_order';
827
828 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
829 $object = new CommandeFournisseur($this->db);
830 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
831 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
832 $object = new Project($this->db);
833 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
834 $modulepart = 'project_task';
835
836 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
837 $object = new Task($this->db);
838
839 $task_result = $object->fetch(0, $ref);
840
841 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
842 if ($task_result > 0) {
843 $project_result = $object->fetchProject();
844
845 if ($project_result >= 0) {
846 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
847 }
848 } else {
849 throw new RestException(500, 'Error while fetching Task '.$ref);
850 }
851 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
852 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
853 $object = new Product($this->db);
854 } elseif ($modulepart == 'expensereport') {
855 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
856 $object = new ExpenseReport($this->db);
857 } elseif ($modulepart == 'ficheinter' || $modulepart == 'intervention') {
858 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
859 $object = new Fichinter($this->db);
860 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
861 $modulepart = 'adherent';
862 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
863 $object = new Adherent($this->db);
864 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
865 $modulepart = 'propale';
866 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
867 $object = new Propal($this->db);
868 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
869 $modulepart = 'agenda';
870 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
871 $object = new ActionComm($this->db);
872 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
873 $modulepart = 'contact';
874 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
875 $object = new Contact($this->db);
876 $fetchbyid = true;
877 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
878 $modulepart = 'contrat';
879 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
880 $object = new Contrat($this->db);
881 } elseif ($modulepart == 'mrp') {
882 $modulepart = 'mrp';
883 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
884 $object = new Mo($this->db);
885 } elseif ($modulepart == 'ecm') {
886 throw new RestException(500, 'Using a non empty "ref" is not compatible with using modulepart = '.$modulepart);
887 } else {
888 // TODO Implement additional moduleparts
889 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
890 }
891
892 if (is_object($object)) {
893 if ($fetchbyid) {
894 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
895 $result = $object->fetch((int) $ref);
896 } else {
897 $result = $object->fetch(0, $ref);
898 }
899
900 if ($result == 0) {
901 throw new RestException(404, "Object with ref '".$ref."' was not found.");
902 } elseif ($result < 0) {
903 throw new RestException(500, 'Error while fetching object: '.$object->error);
904 }
905 }
906
907 if (!($object->id > 0)) {
908 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
909 }
910
911 // Special cases that need to use get_exdir to get real dir of object
912 // In future, all object should use this to define path of documents.
913 if ($modulepart == 'supplier_invoice') {
914 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
915 }
916
917 // Test on permissions
918 //if ($modulepart != 'ecm') { // Here $modulepart is always != 'ecm'
919 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
920 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
921 $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
922 /*} else {
923 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
924 throw new RestException(403, 'Missing permission to upload files in ECM module');
925 }
926 $upload_dir = $conf->medias->multidir_output[$conf->entity];
927 }*/
928
929 if (empty($upload_dir) || $upload_dir == '/') {
930 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.');
931 }
932 } else {
933 if ($modulepart == 'invoice') {
934 $modulepart = 'facture';
935 }
936 if ($modulepart == 'member') {
937 $modulepart = 'adherent';
938 }
939
940 // Test on permissions
941 if ($modulepart != 'ecm') {
942 $relativefile = $subdir;
943 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
944 $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
945 } else {
946 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
947 throw new RestException(403, 'Missing permission to upload files in ECM module');
948 }
949 $upload_dir = $conf->medias->multidir_output[$conf->entity];
950 }
951
952 if (empty($upload_dir) || $upload_dir == '/') {
953 if (!empty($tmp['error'])) {
954 throw new RestException(403, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
955 } else {
956 throw new RestException(400, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
957 }
958 }
959 }
960 // $original_file here is still value of filename without any dir.
961
962 $upload_dir = dol_sanitizePathName($upload_dir);
963
964 if (!empty($createdirifnotexists)) {
965 if (dol_mkdir($upload_dir) < 0) { // needed by products
966 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
967 }
968 }
969
970 $destfile = $upload_dir.'/'.$original_file;
971 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
972 dol_delete_file($destfiletmp);
973 //var_dump($original_file);exit;
974
975 if (!dol_is_dir(dirname($destfile))) {
976 throw new RestException(400, 'Directory does not exists : '.dirname($destfile));
977 }
978
979 if (!$overwriteifexists && dol_is_file($destfile)) {
980 throw new RestException(400, "File with name '".$original_file."' already exists.");
981 }
982
983 // in case temporary directory admin/temp doesn't exist
984 if (!dol_is_dir(dirname($destfiletmp))) {
985 dol_mkdir(dirname($destfiletmp));
986 }
987
988 $fhandle = @fopen($destfiletmp, 'w');
989 if ($fhandle) {
990 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
991 fclose($fhandle);
992 dolChmod($destfiletmp);
993 } else {
994 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
995 }
996
997 $disablevirusscan = 0;
998 $src_file = $destfiletmp;
999 $dest_file = $destfile;
1000
1001 // Security:
1002 // If we need to make a virus scan
1003 if (empty($disablevirusscan) && file_exists($src_file)) {
1004 $checkvirusarray = dolCheckVirus($src_file, $dest_file);
1005 if (count($checkvirusarray)) {
1006 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.implode(',', $checkvirusarray), LOG_WARNING);
1007 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.implode(',', $checkvirusarray));
1008 }
1009 }
1010
1011 // Security:
1012 // Disallow file with some extensions. We rename them.
1013 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
1014 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
1015 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
1016 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
1017 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
1018 $publicmediasdirwithslash .= '/';
1019 }
1020
1021 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
1022 $dest_file .= '.noexe';
1023 }
1024 }
1025
1026 // Security:
1027 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1028 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
1029 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
1030 throw new RestException(500, "Refused to deliver file ".$src_file);
1031 }
1032
1033 // Security:
1034 // We refuse cache files/dirs, upload using .. and pipes into filenames.
1035 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
1036 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
1037 throw new RestException(500, "Refused to deliver file ".$dest_file);
1038 }
1039
1040 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
1041 if (!empty($object) && is_object($object) && $object->id > 0) {
1042 $moreinfo['src_object_type'] = $object->table_element;
1043 $moreinfo['src_object_id'] = $object->id;
1044 }
1045 if (!empty($array_options)) {
1046 $moreinfo = array_merge($moreinfo, ["array_options" => $array_options]);
1047 }
1048 if (!empty($position)) {
1049 $moreinfo = array_merge($moreinfo, ["position" => $position]);
1050 }
1051 if (!empty($cover)) {
1052 $moreinfo = array_merge($moreinfo, ["cover" => $cover]);
1053 }
1054 $moreinfo['gen_or_uploaded'] = 'api';
1055
1056 // Move the temporary file at its final emplacement
1057 $result = dol_move($destfiletmp, $dest_file, '0', $overwriteifexists, 1, 1, $moreinfo);
1058 if (!$result) {
1059 throw new RestException(500, "Failed to move file into '".$dest_file."'");
1060 }
1061
1062 if (is_object($object) && $generateThumbs) {
1063 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1064 if (image_format_supported($dest_file)) {
1065 $object->addThumbs($dest_file);
1066 }
1067 }
1068
1069 return dol_basename($destfile);
1070 }
1071
1091 public function delete($modulepart, $original_file)
1092 {
1093 global $conf;
1094
1095 if (empty($modulepart)) {
1096 throw new RestException(400, 'bad value for parameter modulepart');
1097 }
1098 if (empty($original_file)) {
1099 throw new RestException(400, 'bad value for parameter original_file');
1100 }
1101
1102 //--- Finds and returns the document
1103 $entity = $conf->entity;
1104
1105 // Special cases that need to use get_exdir to get real dir of object
1106 // If future, all object should use this to define path of documents.
1107 /*
1108 $tmpreldir = '';
1109 if ($modulepart == 'supplier_invoice') {
1110 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
1111 }
1112
1113 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
1114 $relativefile = $original_file;
1115
1116 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
1117 $accessallowed = $check_access['accessallowed'];
1118 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
1119 $original_file = $check_access['original_file'];
1120
1121 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
1122 throw new RestException(403);
1123 }
1124 if (!$accessallowed) {
1125 throw new RestException(403);
1126 }
1127
1128 if (DolibarrApiAccess::$user->socid > 0) {
1129 if ($sqlprotectagainstexternals) {
1130 $resql = $this->db->query($sqlprotectagainstexternals);
1131 if ($resql) {
1132 $num = $this->db->num_rows($resql);
1133 $i = 0;
1134 while ($i < $num) {
1135 $obj = $this->db->fetch_object($resql);
1136 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
1137 throw new RestException(403, 'Not allowed to download documents with such a ref');
1138 }
1139 $i++;
1140 }
1141 }
1142 }
1143 }
1144
1145 $filename = basename($original_file);
1146 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
1147
1148 if (!file_exists($original_file_osencoded)) {
1149 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
1150 throw new RestException(404, 'File not found');
1151 }
1152
1153 if (@unlink($original_file_osencoded)) {
1154 return array(
1155 'success' => array(
1156 'code' => 200,
1157 'message' => 'Document deleted'
1158 )
1159 );
1160 }
1161
1162 throw new RestException(403);
1163 }
1164}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
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.
API class for receive files.
__construct()
Constructor.
index($modulepart, $original_file='')
Download a document.
builddoc($modulepart, $original_file='', $doctemplate='', $langcode='')
Build a document.
post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='', $overwriteifexists=0, $createdirifnotexists=1, $position=0, $cover='', $array_options=[], $generateThumbs=0)
Return a document.
Class for API REST v1.
Definition api.class.php:33
Class to manage ECM files.
Class to manage Trips and Expenses.
Class to manage suppliers invoices.
Class to manage invoices.
Class for KnowledgeRecord.
Class for Mo.
Definition mo.class.php:35
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.
dol_basename($pathfile)
Make a basename working with all page code (default PHP basenamed fails with cyrillic).
Definition files.lib.php:38
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array(), $entity=0)
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=null, $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.
dolCheckVirus($src_file, $dest_file='')
Check virus into a file.
dol_dir_list($utf8_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:63
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.
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
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)
image_format_supported($file, $acceptsvg=0)
Return if a filename is file name of a supported image format.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79