dolibarr 20.0.5
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;
23
24require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
25require_once DOL_DOCUMENT_ROOT.'/api/class/api.class.php';
26require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
27
35{
39 public function __construct()
40 {
41 global $db;
42 $this->db = $db;
43 }
44
45
62 public function index($modulepart, $original_file = '')
63 {
64 global $conf;
65
66 if (empty($modulepart)) {
67 throw new RestException(400, 'bad value for parameter modulepart');
68 }
69 if (empty($original_file)) {
70 throw new RestException(400, 'bad value for parameter original_file');
71 }
72
73 //--- Finds and returns the document
74 $entity = $conf->entity;
75
76 // Special cases that need to use get_exdir to get real dir of object
77 // If future, all object should use this to define path of documents.
78 /*
79 $tmpreldir = '';
80 if ($modulepart == 'supplier_invoice') {
81 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
82 }
83
84 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
85 $relativefile = $original_file;
86
87 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
88 $accessallowed = $check_access['accessallowed'];
89 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
90 $original_file = $check_access['original_file'];
91
92 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
93 throw new RestException(403);
94 }
95 if (!$accessallowed) {
96 throw new RestException(403);
97 }
98
99 if (DolibarrApiAccess::$user->socid > 0) {
100 if ($sqlprotectagainstexternals) {
101 $resql = $this->db->query($sqlprotectagainstexternals);
102 if ($resql) {
103 $num = $this->db->num_rows($resql);
104 $i = 0;
105 while ($i < $num) {
106 $obj = $this->db->fetch_object($resql);
107 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
108 throw new RestException(403, 'Not allowed to download documents with such a ref');
109 }
110 $i++;
111 }
112 }
113 }
114 }
115
116 $filename = basename($original_file);
117 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
118
119 if (!file_exists($original_file_osencoded)) {
120 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
121 throw new RestException(404, 'File not found');
122 }
123
124 $file_content = file_get_contents($original_file_osencoded);
125 return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'encoding'=>'base64');
126 }
127
128
150 public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
151 {
152 global $conf, $langs;
153
154 if (empty($modulepart)) {
155 throw new RestException(400, 'bad value for parameter modulepart');
156 }
157 if (empty($original_file)) {
158 throw new RestException(400, 'bad value for parameter original_file');
159 }
160
161 $outputlangs = $langs;
162 if ($langcode && $langs->defaultlang != $langcode) {
163 $outputlangs = new Translate('', $conf);
164 $outputlangs->setDefaultLang($langcode);
165 }
166
167 //--- Finds and returns the document
168 $entity = $conf->entity;
169
170 // Special cases that need to use get_exdir to get real dir of object
171 // If future, all object should use this to define path of documents.
172 /*
173 $tmpreldir = '';
174 if ($modulepart == 'supplier_invoice') {
175 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
176 }
177
178 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
179 $relativefile = $original_file;
180
181 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
182 $accessallowed = $check_access['accessallowed'];
183 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
184 $original_file = $check_access['original_file'];
185
186 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
187 throw new RestException(403);
188 }
189 if (!$accessallowed) {
190 throw new RestException(403);
191 }
192
193 if (DolibarrApiAccess::$user->socid > 0) {
194 if ($sqlprotectagainstexternals) {
195 $resql = $this->db->query($sqlprotectagainstexternals);
196 if ($resql) {
197 $num = $this->db->num_rows($resql);
198 $i = 0;
199 while ($i < $num) {
200 $obj = $this->db->fetch_object($resql);
201 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
202 throw new RestException(403, 'Not allowed to download documents with such a ref');
203 }
204 $i++;
205 }
206 }
207 }
208 }
209
210 // --- Generates the document
211 $hidedetails = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1;
212 $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1;
213 $hideref = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 0 : 1;
214
215 $templateused = '';
216
217 if ($modulepart == 'facture' || $modulepart == 'invoice') {
218 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
219 $tmpobject = new Facture($this->db);
220 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
221 if (!$result) {
222 throw new RestException(404, 'Invoice not found');
223 }
224
225 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
226 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
227 if ($result <= 0) {
228 throw new RestException(500, 'Error generating document');
229 }
230 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
231 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
232 $tmpobject = new FactureFournisseur($this->db);
233 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
234 if (!$result) {
235 throw new RestException(404, 'Supplier invoice not found');
236 }
237
238 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
239 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
240 if ($result < 0) {
241 throw new RestException(500, 'Error generating document');
242 }
243 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
244 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
245 $tmpobject = new Commande($this->db);
246 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
247 if (!$result) {
248 throw new RestException(404, 'Order not found');
249 }
250 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
251 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
252 if ($result <= 0) {
253 throw new RestException(500, 'Error generating document');
254 }
255 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
256 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
257 $tmpobject = new Propal($this->db);
258 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
259 if (!$result) {
260 throw new RestException(404, 'Proposal not found');
261 }
262 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
263 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
264 if ($result <= 0) {
265 throw new RestException(500, 'Error generating document');
266 }
267 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
268 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
269
270 $tmpobject = new Contrat($this->db);
271 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
272
273 if (!$result) {
274 throw new RestException(404, 'Contract not found');
275 }
276
277 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
278 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
279
280 if ($result <= 0) {
281 throw new RestException(500, 'Error generating document missing doctemplate parameter');
282 }
283 } elseif ($modulepart == 'expedition' || $modulepart == 'shipment') {
284 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
285
286 $tmpobject = new Expedition($this->db);
287 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
288
289 if (!$result) {
290 throw new RestException(404, 'Shipment not found');
291 }
292
293 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
294 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
295
296 if ($result <= 0) {
297 throw new RestException(500, 'Error generating document missing doctemplate parameter');
298 }
299 } elseif ($modulepart == 'mrp') {
300 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
301
302 $tmpobject = new Mo($this->db);
303 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
304
305 if (!$result) {
306 throw new RestException(404, 'MO not found');
307 }
308
309 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
310 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
311
312 if ($result <= 0) {
313 throw new RestException(500, 'Error generating document missing doctemplate parameter');
314 }
315 } else {
316 throw new RestException(403, 'Generation not available for this modulepart');
317 }
318
319 $filename = basename($original_file);
320 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
321
322 if (!file_exists($original_file_osencoded)) {
323 throw new RestException(404, 'File not found');
324 }
325
326 $file_content = file_get_contents($original_file_osencoded);
327 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');
328 }
329
350 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
351 {
352 global $conf;
353
354 if (empty($modulepart)) {
355 throw new RestException(400, 'bad value for parameter modulepart');
356 }
357
358 if (empty($id) && empty($ref)) {
359 throw new RestException(400, 'bad value for parameter id or ref');
360 }
361
362 $id = (empty($id) ? 0 : $id);
363 $recursive = 0;
364 $type = 'files';
365
366 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
367 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
368
369 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
370 throw new RestException(403);
371 }
372
373 $object = new Societe($this->db);
374 $result = $object->fetch($id, $ref);
375 if (!$result) {
376 throw new RestException(404, 'Thirdparty not found');
377 }
378
379 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
380 } elseif ($modulepart == 'user') {
381 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
382
383 // Can get doc if has permission to read all user or if it is user itself
384 if (!DolibarrApiAccess::$user->hasRight('user', 'user', 'lire') && DolibarrApiAccess::$user->id != $id) {
385 throw new RestException(403);
386 }
387
388 $object = new User($this->db);
389 $result = $object->fetch($id, $ref);
390 if (!$result) {
391 throw new RestException(404, 'User not found');
392 }
393
394 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
395 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
396 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
397
398 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
399 throw new RestException(403);
400 }
401
402 $object = new Adherent($this->db);
403 $result = $object->fetch($id, $ref);
404 if (!$result) {
405 throw new RestException(404, 'Member not found');
406 }
407
408 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
409 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
410 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
411
412 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
413 throw new RestException(403);
414 }
415
416 $object = new Propal($this->db);
417 $result = $object->fetch($id, $ref);
418 if (!$result) {
419 throw new RestException(404, 'Proposal not found');
420 }
421
422 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
423 } elseif ($modulepart == 'supplier_proposal') {
424 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
425
426 if (!DolibarrApiAccess::$user->hasRight('supplier_proposal', 'read')) {
427 throw new RestException(403);
428 }
429
430 $object = new Propal($this->db);
431 $result = $object->fetch($id, $ref);
432 if (!$result) {
433 throw new RestException(404, 'Supplier proposal not found');
434 }
435
436 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
437 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
438 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
439
440 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
441 throw new RestException(403);
442 }
443
444 $object = new Commande($this->db);
445 $result = $object->fetch($id, $ref);
446 if (!$result) {
447 throw new RestException(404, 'Order not found');
448 }
449
450 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
451 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
452 $modulepart = 'supplier_order';
453
454 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
455
456 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'commande', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_order', 'lire')) {
457 throw new RestException(403);
458 }
459
460 $object = new CommandeFournisseur($this->db);
461 $result = $object->fetch($id, $ref);
462 if (!$result) {
463 throw new RestException(404, 'Purchase order not found');
464 }
465
466 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
467 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
468 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
469
470 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
471 throw new RestException(403);
472 }
473
474 $object = new Expedition($this->db);
475 $result = $object->fetch($id, $ref);
476 if (!$result) {
477 throw new RestException(404, 'Shipment not found');
478 }
479
480 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
481 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
482 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
483
484 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
485 throw new RestException(403);
486 }
487
488 $object = new Facture($this->db);
489 $result = $object->fetch($id, $ref);
490 if (!$result) {
491 throw new RestException(404, 'Invoice not found');
492 }
493
494 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
495 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
496 $modulepart = 'supplier_invoice';
497
498 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
499
500 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'facture', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_invoice', 'lire')) {
501 throw new RestException(403);
502 }
503
504 $object = new FactureFournisseur($this->db);
505 $result = $object->fetch($id, $ref);
506 if (!$result) {
507 throw new RestException(404, 'Invoice not found');
508 }
509
510 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
511 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
512 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
513
514 if (!DolibarrApiAccess::$user->hasRight('produit', 'lire')) {
515 throw new RestException(403);
516 }
517
518 $object = new Product($this->db);
519 $result = $object->fetch($id, $ref);
520 if ($result == 0) {
521 throw new RestException(404, 'Product not found');
522 } elseif ($result < 0) {
523 throw new RestException(500, 'Error while fetching object: '.$object->error);
524 }
525
526 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
527 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
528 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
529
530 if (!DolibarrApiAccess::$user->hasRight('agenda', 'myactions', 'read') && !DolibarrApiAccess::$user->hasRight('agenda', 'allactions', 'read')) {
531 throw new RestException(403);
532 }
533
534 $object = new ActionComm($this->db);
535 $result = $object->fetch($id, $ref);
536 if (!$result) {
537 throw new RestException(404, 'Event not found');
538 }
539
540 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
541 } elseif ($modulepart == 'expensereport') {
542 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
543
544 if (!DolibarrApiAccess::$user->hasRight('expensereport', 'read')) {
545 throw new RestException(403);
546 }
547
548 $object = new ExpenseReport($this->db);
549 $result = $object->fetch($id, $ref);
550 if (!$result) {
551 throw new RestException(404, 'Expense report not found');
552 }
553
554 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
555 } elseif ($modulepart == 'knowledgemanagement') {
556 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
557
558 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
559 throw new RestException(403);
560 }
561
562 $object = new KnowledgeRecord($this->db);
563 $result = $object->fetch($id, $ref);
564 if (!$result) {
565 throw new RestException(404, 'KM article not found');
566 }
567
568 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
569 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
570 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
571
572 if (!DolibarrApiAccess::$user->hasRight('categorie', 'lire')) {
573 throw new RestException(403);
574 }
575
576 $object = new Categorie($this->db);
577 $result = $object->fetch($id, $ref);
578 if (!$result) {
579 throw new RestException(404, 'Category not found');
580 }
581
582 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
583 } elseif ($modulepart == 'ecm') {
584 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
585 // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
586
587 // if (!DolibarrApiAccess::$user->hasRight('ecm', 'read')) {
588 // throw new RestException(403);
589 // }
590
591 // // $object = new EcmDirectory($this->db);
592 // // $result = $object->fetch($ref);
593 // // if (!$result) {
594 // // throw new RestException(404, 'EcmDirectory not found');
595 // // }
596 // $upload_dir = $conf->ecm->dir_output;
597 // $type = 'all';
598 // $recursive = 0;
599 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
600 $modulepart = 'contrat';
601 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
602
603 $object = new Contrat($this->db);
604 $result = $object->fetch($id, $ref);
605 if (!$result) {
606 throw new RestException(404, 'Contract not found');
607 }
608
609 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
610 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
611 $modulepart = 'project';
612 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
613
614 $object = new Project($this->db);
615 $result = $object->fetch($id, $ref);
616 if (!$result) {
617 throw new RestException(404, 'Project not found');
618 }
619
620 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
621 } elseif ($modulepart == 'mrp') {
622 $modulepart = 'mrp';
623 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
624
625 $object = new Mo($this->db);
626 $result = $object->fetch($id, $ref);
627 if (!$result) {
628 throw new RestException(404, 'MO not found');
629 }
630
631 $upload_dir = $conf->mrp->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'mrp');
632 } else {
633 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
634 }
635
636 $objectType = $modulepart;
637 if (! empty($object->id) && ! empty($object->table_element)) {
638 $objectType = $object->table_element;
639 }
640
641 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
642 if (empty($filearray)) {
643 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
644 } else {
645 if (($object->id) > 0 && !empty($modulepart)) {
646 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
647 $ecmfile = new EcmFiles($this->db);
648 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
649 if ($result < 0) {
650 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
651 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
652 $count = count($filearray);
653 for ($i = 0 ; $i < $count ; $i++) {
654 foreach ($ecmfile->lines as $line) {
655 if ($filearray[$i]['name'] == $line->filename) {
656 $filearray[$i] = array_merge($filearray[$i], (array) $line);
657 }
658 }
659 }
660 }
661 }
662 }
663
664 return $filearray;
665 }
666
667
676 /*
677 public function get($id) {
678 return array('note'=>'xxx');
679 }*/
680
681
708 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1)
709 {
710 global $conf;
711
712 //var_dump($modulepart);
713 //var_dump($filename);
714 //var_dump($filecontent);exit;
715
716 $modulepartorig = $modulepart;
717
718 if (empty($modulepart)) {
719 throw new RestException(400, 'Modulepart not provided.');
720 }
721
722 $newfilecontent = '';
723 if (empty($fileencoding)) {
724 $newfilecontent = $filecontent;
725 }
726 if ($fileencoding == 'base64') {
727 $newfilecontent = base64_decode($filecontent);
728 }
729
730 $original_file = dol_sanitizeFileName($filename);
731
732 // Define $uploadir
733 $object = null;
734 $entity = DolibarrApiAccess::$user->entity;
735 if (empty($entity)) {
736 $entity = 1;
737 }
738
739 if ($ref) {
740 $tmpreldir = '';
741 $fetchbyid = false;
742
743 if ($modulepart == 'facture' || $modulepart == 'invoice') {
744 $modulepart = 'facture';
745
746 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
747 $object = new Facture($this->db);
748 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
749 $modulepart = 'supplier_invoice';
750
751 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
752 $object = new FactureFournisseur($this->db);
753 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
754 $modulepart = 'commande';
755
756 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
757 $object = new Commande($this->db);
758 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
759 $modulepart = 'supplier_order';
760
761 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
762 $object = new CommandeFournisseur($this->db);
763 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
764 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
765 $object = new Project($this->db);
766 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
767 $modulepart = 'project_task';
768
769 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
770 $object = new Task($this->db);
771
772 $task_result = $object->fetch('', $ref);
773
774 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
775 if ($task_result > 0) {
776 $project_result = $object->fetch_projet();
777
778 if ($project_result >= 0) {
779 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
780 }
781 } else {
782 throw new RestException(500, 'Error while fetching Task '.$ref);
783 }
784 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
785 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
786 $object = new Product($this->db);
787 } elseif ($modulepart == 'expensereport') {
788 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
789 $object = new ExpenseReport($this->db);
790 } elseif ($modulepart == 'fichinter') {
791 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
792 $object = new Fichinter($this->db);
793 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
794 $modulepart = 'adherent';
795 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
796 $object = new Adherent($this->db);
797 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
798 $modulepart = 'propale';
799 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
800 $object = new Propal($this->db);
801 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
802 $modulepart = 'agenda';
803 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
804 $object = new ActionComm($this->db);
805 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
806 $modulepart = 'contact';
807 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
808 $object = new Contact($this->db);
809 $fetchbyid = true;
810 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
811 $modulepart = 'contrat';
812 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
813 $object = new Contrat($this->db);
814 } elseif ($modulepart == 'mrp') {
815 $modulepart = 'mrp';
816 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
817 $object = new Mo($this->db);
818 } else {
819 // TODO Implement additional moduleparts
820 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
821 }
822
823 if (is_object($object)) {
824 if ($fetchbyid) {
825 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
826 $result = $object->fetch($ref);
827 } else {
828 $result = $object->fetch('', $ref);
829 }
830
831 if ($result == 0) {
832 throw new RestException(404, "Object with ref '".$ref."' was not found.");
833 } elseif ($result < 0) {
834 throw new RestException(500, 'Error while fetching object: '.$object->error);
835 }
836 }
837
838 if (!($object->id > 0)) {
839 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
840 }
841
842 // Special cases that need to use get_exdir to get real dir of object
843 // In future, all object should use this to define path of documents.
844 if ($modulepart == 'supplier_invoice') {
845 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
846 }
847
848 // Test on permissions
849 if ($modulepart != 'ecm') {
850 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
851 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
852 $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
853 } else {
854 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
855 throw new RestException(403, 'Missing permission to upload files in ECM module');
856 }
857 $upload_dir = $conf->medias->multidir_output[$conf->entity];
858 }
859
860 if (empty($upload_dir) || $upload_dir == '/') {
861 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.');
862 }
863 } else {
864 if ($modulepart == 'invoice') {
865 $modulepart = 'facture';
866 }
867 if ($modulepart == 'member') {
868 $modulepart = 'adherent';
869 }
870
871 // Test on permissions
872 if ($modulepart != 'ecm') {
873 $relativefile = $subdir;
874 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
875 $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
876 } else {
877 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
878 throw new RestException(403, 'Missing permission to upload files in ECM module');
879 }
880 $upload_dir = $conf->medias->multidir_output[$conf->entity];
881 }
882
883 if (empty($upload_dir) || $upload_dir == '/') {
884 if (!empty($tmp['error'])) {
885 throw new RestException(403, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
886 } else {
887 throw new RestException(400, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
888 }
889 }
890 }
891 // $original_file here is still value of filename without any dir.
892
893 $upload_dir = dol_sanitizePathName($upload_dir);
894
895 if (!empty($createdirifnotexists)) {
896 if (dol_mkdir($upload_dir) < 0) { // needed by products
897 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
898 }
899 }
900
901 $destfile = $upload_dir.'/'.$original_file;
902 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
903 dol_delete_file($destfiletmp);
904 //var_dump($original_file);exit;
905
906 if (!dol_is_dir(dirname($destfile))) {
907 throw new RestException(400, 'Directory does not exists : '.dirname($destfile));
908 }
909
910 if (!$overwriteifexists && dol_is_file($destfile)) {
911 throw new RestException(400, "File with name '".$original_file."' already exists.");
912 }
913
914 // in case temporary directory admin/temp doesn't exist
915 if (!dol_is_dir(dirname($destfiletmp))) {
916 dol_mkdir(dirname($destfiletmp));
917 }
918
919 $fhandle = @fopen($destfiletmp, 'w');
920 if ($fhandle) {
921 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
922 fclose($fhandle);
923 dolChmod($destfiletmp);
924 } else {
925 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
926 }
927
928 $disablevirusscan = 0;
929 $src_file = $destfiletmp;
930 $dest_file = $destfile;
931
932 // Security:
933 // If we need to make a virus scan
934 if (empty($disablevirusscan) && file_exists($src_file)) {
935 $checkvirusarray = dolCheckVirus($src_file, $dest_file);
936 if (count($checkvirusarray)) {
937 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.implode(',', $checkvirusarray), LOG_WARNING);
938 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.implode(',', $checkvirusarray));
939 }
940 }
941
942 // Security:
943 // Disallow file with some extensions. We rename them.
944 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
945 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
946 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
947 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
948 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
949 $publicmediasdirwithslash .= '/';
950 }
951
952 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
953 $dest_file .= '.noexe';
954 }
955 }
956
957 // Security:
958 // We refuse cache files/dirs, upload using .. and pipes into filenames.
959 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
960 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
961 throw new RestException(500, "Refused to deliver file ".$src_file);
962 }
963
964 // Security:
965 // We refuse cache files/dirs, upload using .. and pipes into filenames.
966 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
967 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
968 throw new RestException(500, "Refused to deliver file ".$dest_file);
969 }
970
971 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
972 if (!empty($object) && is_object($object) && $object->id > 0) {
973 $moreinfo['src_object_type'] = $object->table_element;
974 $moreinfo['src_object_id'] = $object->id;
975 }
976
977 // Move the temporary file at its final emplacement
978 $result = dol_move($destfiletmp, $dest_file, 0, $overwriteifexists, 1, 1, $moreinfo);
979 if (!$result) {
980 throw new RestException(500, "Failed to move file into '".$dest_file."'");
981 }
982
983 return dol_basename($destfile);
984 }
985
1001 public function delete($modulepart, $original_file)
1002 {
1003 global $conf, $langs;
1004
1005 if (empty($modulepart)) {
1006 throw new RestException(400, 'bad value for parameter modulepart');
1007 }
1008 if (empty($original_file)) {
1009 throw new RestException(400, 'bad value for parameter original_file');
1010 }
1011
1012 //--- Finds and returns the document
1013 $entity = $conf->entity;
1014
1015 // Special cases that need to use get_exdir to get real dir of object
1016 // If future, all object should use this to define path of documents.
1017 /*
1018 $tmpreldir = '';
1019 if ($modulepart == 'supplier_invoice') {
1020 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
1021 }
1022
1023 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
1024 $relativefile = $original_file;
1025
1026 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
1027 $accessallowed = $check_access['accessallowed'];
1028 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
1029 $original_file = $check_access['original_file'];
1030
1031 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
1032 throw new RestException(403);
1033 }
1034 if (!$accessallowed) {
1035 throw new RestException(403);
1036 }
1037
1038 if (DolibarrApiAccess::$user->socid > 0) {
1039 if ($sqlprotectagainstexternals) {
1040 $resql = $this->db->query($sqlprotectagainstexternals);
1041 if ($resql) {
1042 $num = $this->db->num_rows($resql);
1043 $i = 0;
1044 while ($i < $num) {
1045 $obj = $this->db->fetch_object($resql);
1046 if (DolibarrApiAccess::$user->socid != $obj->fk_soc) {
1047 throw new RestException(403, 'Not allowed to download documents with such a ref');
1048 }
1049 $i++;
1050 }
1051 }
1052 }
1053 }
1054
1055 $filename = basename($original_file);
1056 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
1057
1058 if (!file_exists($original_file_osencoded)) {
1059 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
1060 throw new RestException(404, 'File not found');
1061 }
1062
1063 if (@unlink($original_file_osencoded)) {
1064 return array(
1065 'success' => array(
1066 'code' => 200,
1067 'message' => 'Document deleted'
1068 )
1069 );
1070 }
1071
1072 throw new RestException(403);
1073 }
1074}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
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.
Class for API REST v1.
Definition api.class.php:31
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 for Mo.
Definition mo.class.php:37
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_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_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
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.
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)