dolibarr 21.0.3
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) 2024 Frédéric France <frederic.france@free.fr>
7 * Copyright (C) 2025 William Mead <william@m34d.com>
8 *
9 * This program is free software you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23use Luracast\Restler\RestException;
24
25require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
26require_once DOL_DOCUMENT_ROOT.'/api/class/api.class.php';
27require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
28
36{
40 public function __construct()
41 {
42 global $db;
43 $this->db = $db;
44 }
45
46
63 public function index($modulepart, $original_file = '')
64 {
65 global $conf;
66
67 if (empty($modulepart)) {
68 throw new RestException(400, 'bad value for parameter modulepart');
69 }
70 if (empty($original_file)) {
71 throw new RestException(400, 'bad value for parameter original_file');
72 }
73
74 //--- Finds and returns the document
75 $entity = $conf->entity;
76
77 // Special cases that need to use get_exdir to get real dir of object
78 // If future, all object should use this to define path of documents.
79 /*
80 $tmpreldir = '';
81 if ($modulepart == 'supplier_invoice') {
82 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
83 }
84
85 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
86 $relativefile = $original_file;
87
88 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
89 $accessallowed = $check_access['accessallowed'];
90 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
91 $original_file = $check_access['original_file'];
92
93 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
94 throw new RestException(403);
95 }
96 if (!$accessallowed) {
97 throw new RestException(403);
98 }
99
100 $filename = basename($original_file);
101 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
102
103 if (!file_exists($original_file_osencoded)) {
104 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
105 throw new RestException(404, 'File not found');
106 }
107
108 $file_content = file_get_contents($original_file_osencoded);
109 return array('filename'=>$filename, 'content-type' => dol_mimetype($filename), 'filesize'=>filesize($original_file), 'content'=>base64_encode($file_content), 'encoding'=>'base64');
110 }
111
112
134 public function builddoc($modulepart, $original_file = '', $doctemplate = '', $langcode = '')
135 {
136 global $conf, $langs;
137
138 if (empty($modulepart)) {
139 throw new RestException(400, 'bad value for parameter modulepart');
140 }
141 if (empty($original_file)) {
142 throw new RestException(400, 'bad value for parameter original_file');
143 }
144
145 $outputlangs = $langs;
146 if ($langcode && $langs->defaultlang != $langcode) {
147 $outputlangs = new Translate('', $conf);
148 $outputlangs->setDefaultLang($langcode);
149 }
150
151 //--- Finds and returns the document
152 $entity = $conf->entity;
153
154 // Special cases that need to use get_exdir to get real dir of object
155 // If future, all object should use this to define path of documents.
156 /*
157 $tmpreldir = '';
158 if ($modulepart == 'supplier_invoice') {
159 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
160 }
161
162 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
163 $relativefile = $original_file;
164
165 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
166 $accessallowed = $check_access['accessallowed'];
167 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
168 $original_file = $check_access['original_file'];
169
170 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
171 throw new RestException(403);
172 }
173 if (!$accessallowed) {
174 throw new RestException(403);
175 }
176
177 // --- Generates the document
178 $hidedetails = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1;
179 $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1;
180 $hideref = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 0 : 1;
181
182 $templateused = '';
183
184 if ($modulepart == 'facture' || $modulepart == 'invoice') {
185 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
186 $tmpobject = new Facture($this->db);
187 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
188 if (!$result) {
189 throw new RestException(404, 'Invoice not found');
190 }
191
192 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
193 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
194 if ($result <= 0) {
195 throw new RestException(500, 'Error generating document');
196 }
197 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') {
198 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
199 $tmpobject = new FactureFournisseur($this->db);
200 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
201 if (!$result) {
202 throw new RestException(404, 'Supplier invoice not found');
203 }
204
205 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
206 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
207 if ($result < 0) {
208 throw new RestException(500, 'Error generating document');
209 }
210 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
211 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
212 $tmpobject = new Commande($this->db);
213 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
214 if (!$result) {
215 throw new RestException(404, 'Order not found');
216 }
217 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
218 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
219 if ($result <= 0) {
220 throw new RestException(500, 'Error generating document');
221 }
222 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
223 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
224 $tmpobject = new Propal($this->db);
225 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
226 if (!$result) {
227 throw new RestException(404, 'Proposal not found');
228 }
229 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
230 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
231 if ($result <= 0) {
232 throw new RestException(500, 'Error generating document');
233 }
234 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
235 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
236
237 $tmpobject = new Contrat($this->db);
238 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
239
240 if (!$result) {
241 throw new RestException(404, 'Contract not found');
242 }
243
244 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
245 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
246
247 if ($result <= 0) {
248 throw new RestException(500, 'Error generating document missing doctemplate parameter');
249 }
250 } elseif ($modulepart == 'expedition' || $modulepart == 'shipment') {
251 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
252
253 $tmpobject = new Expedition($this->db);
254 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
255
256 if (!$result) {
257 throw new RestException(404, 'Shipment not found');
258 }
259
260 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
261 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
262
263 if ($result <= 0) {
264 throw new RestException(500, 'Error generating document missing doctemplate parameter');
265 }
266 } elseif ($modulepart == 'mrp') {
267 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
268
269 $tmpobject = new Mo($this->db);
270 $result = $tmpobject->fetch(0, preg_replace('/\.[^\.]+$/', '', basename($original_file)));
271
272 if (!$result) {
273 throw new RestException(404, 'MO not found');
274 }
275
276 $templateused = $doctemplate ? $doctemplate : $tmpobject->model_pdf;
277 $result = $tmpobject->generateDocument($templateused, $outputlangs, $hidedetails, $hidedesc, $hideref);
278
279 if ($result <= 0) {
280 throw new RestException(500, 'Error generating document missing doctemplate parameter');
281 }
282 } else {
283 throw new RestException(403, 'Generation not available for this modulepart');
284 }
285
286 $filename = basename($original_file);
287 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
288
289 if (!file_exists($original_file_osencoded)) {
290 throw new RestException(404, 'File not found');
291 }
292
293 $file_content = file_get_contents($original_file_osencoded);
294 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');
295 }
296
317 public function getDocumentsListByElement($modulepart, $id = 0, $ref = '', $sortfield = '', $sortorder = '')
318 {
319 global $conf;
320
321 if (empty($modulepart)) {
322 throw new RestException(400, 'bad value for parameter modulepart');
323 }
324
325 if (empty($id) && empty($ref)) {
326 throw new RestException(400, 'bad value for parameter id or ref');
327 }
328
329 $id = (empty($id) ? 0 : $id);
330 $recursive = 0;
331 $type = 'files';
332
333 if ($modulepart == 'societe' || $modulepart == 'thirdparty') {
334 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
335
336 if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
337 throw new RestException(403);
338 }
339
340 $object = new Societe($this->db);
341 $result = $object->fetch($id, $ref);
342 if (!$result) {
343 throw new RestException(404, 'Thirdparty not found');
344 }
345
346 $upload_dir = $conf->societe->multidir_output[$object->entity]."/".$object->id;
347 } elseif ($modulepart == 'user') {
348 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
349
350 // Can get doc if has permission to read all user or if it is user itself
351 if (!DolibarrApiAccess::$user->hasRight('user', 'user', 'lire') && DolibarrApiAccess::$user->id != $id) {
352 throw new RestException(403);
353 }
354
355 $object = new User($this->db);
356 $result = $object->fetch($id, $ref);
357 if (!$result) {
358 throw new RestException(404, 'User not found');
359 }
360
361 $upload_dir = $conf->user->dir_output.'/'.get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id;
362 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
363 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
364
365 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
366 throw new RestException(403);
367 }
368
369 $object = new Adherent($this->db);
370 $result = $object->fetch($id, $ref);
371 if (!$result) {
372 throw new RestException(404, 'Member not found');
373 }
374
375 $upload_dir = $conf->adherent->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'member');
376 } elseif ($modulepart == 'propal' || $modulepart == 'proposal') {
377 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
378
379 if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
380 throw new RestException(403);
381 }
382
383 $object = new Propal($this->db);
384 $result = $object->fetch($id, $ref);
385 if (!$result) {
386 throw new RestException(404, 'Proposal not found');
387 }
388
389 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
390 } elseif ($modulepart == 'supplier_proposal') {
391 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
392
393 if (!DolibarrApiAccess::$user->hasRight('supplier_proposal', 'read')) {
394 throw new RestException(403);
395 }
396
397 $object = new Propal($this->db);
398 $result = $object->fetch($id, $ref);
399 if (!$result) {
400 throw new RestException(404, 'Supplier proposal not found');
401 }
402
403 $upload_dir = $conf->propal->multidir_output[$object->entity]."/".get_exdir(0, 0, 0, 1, $object, 'propal');
404 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
405 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
406
407 if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
408 throw new RestException(403);
409 }
410
411 $object = new Commande($this->db);
412 $result = $object->fetch($id, $ref);
413 if (!$result) {
414 throw new RestException(404, 'Order not found');
415 }
416
417 $upload_dir = $conf->commande->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'commande');
418 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
419 $modulepart = 'supplier_order';
420
421 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
422
423 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'commande', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_order', 'lire')) {
424 throw new RestException(403);
425 }
426
427 $object = new CommandeFournisseur($this->db);
428 $result = $object->fetch($id, $ref);
429 if (!$result) {
430 throw new RestException(404, 'Purchase order not found');
431 }
432
433 $upload_dir = $conf->fournisseur->dir_output."/commande/".dol_sanitizeFileName($object->ref);
434 } elseif ($modulepart == 'shipment' || $modulepart == 'expedition') {
435 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
436
437 if (!DolibarrApiAccess::$user->hasRight('expedition', 'lire')) {
438 throw new RestException(403);
439 }
440
441 $object = new Expedition($this->db);
442 $result = $object->fetch($id, $ref);
443 if (!$result) {
444 throw new RestException(404, 'Shipment not found');
445 }
446
447 $upload_dir = $conf->expedition->dir_output."/sending/".get_exdir(0, 0, 0, 1, $object, 'shipment');
448 } elseif ($modulepart == 'facture' || $modulepart == 'invoice') {
449 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
450
451 if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
452 throw new RestException(403);
453 }
454
455 $object = new Facture($this->db);
456 $result = $object->fetch($id, $ref);
457 if (!$result) {
458 throw new RestException(404, 'Invoice not found');
459 }
460
461 $upload_dir = $conf->facture->dir_output."/".get_exdir(0, 0, 0, 1, $object, 'invoice');
462 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
463 $modulepart = 'supplier_invoice';
464
465 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
466
467 if (!DolibarrApiAccess::$user->hasRight('fournisseur', 'facture', 'lire') && !DolibarrApiAccess::$user->hasRight('supplier_invoice', 'lire')) {
468 throw new RestException(403);
469 }
470
471 $object = new FactureFournisseur($this->db);
472 $result = $object->fetch($id, $ref);
473 if (!$result) {
474 throw new RestException(404, 'Invoice not found');
475 }
476
477 $upload_dir = $conf->fournisseur->dir_output."/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref);
478 } elseif ($modulepart == 'produit' || $modulepart == 'product') {
479 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
480
481 if (!DolibarrApiAccess::$user->hasRight('produit', 'lire')) {
482 throw new RestException(403);
483 }
484
485 $object = new Product($this->db);
486 $result = $object->fetch($id, $ref);
487 if ($result == 0) {
488 throw new RestException(404, 'Product not found');
489 } elseif ($result < 0) {
490 throw new RestException(500, 'Error while fetching object: '.$object->error);
491 }
492
493 $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 1, $object, 'product');
494 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
495 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
496
497 if (!DolibarrApiAccess::$user->hasRight('agenda', 'myactions', 'read') && !DolibarrApiAccess::$user->hasRight('agenda', 'allactions', 'read')) {
498 throw new RestException(403);
499 }
500
501 $object = new ActionComm($this->db);
502 $result = $object->fetch($id, $ref);
503 if (!$result) {
504 throw new RestException(404, 'Event not found');
505 }
506
507 $upload_dir = $conf->agenda->dir_output.'/'.dol_sanitizeFileName($object->ref);
508 } elseif ($modulepart == 'expensereport') {
509 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
510
511 if (!DolibarrApiAccess::$user->hasRight('expensereport', 'read')) {
512 throw new RestException(403);
513 }
514
515 $object = new ExpenseReport($this->db);
516 $result = $object->fetch($id, $ref);
517 if (!$result) {
518 throw new RestException(404, 'Expense report not found');
519 }
520
521 $upload_dir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($object->ref);
522 } elseif ($modulepart == 'knowledgemanagement') {
523 require_once DOL_DOCUMENT_ROOT.'/knowledgemanagement/class/knowledgerecord.class.php';
524
525 if (!DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read') && !DolibarrApiAccess::$user->hasRight('knowledgemanagement', 'knowledgerecord', 'read')) {
526 throw new RestException(403);
527 }
528
529 $object = new KnowledgeRecord($this->db);
530 $result = $object->fetch($id, $ref);
531 if (!$result) {
532 throw new RestException(404, 'KM article not found');
533 }
534
535 $upload_dir = $conf->knowledgemanagement->dir_output.'/knowledgerecord/'.dol_sanitizeFileName($object->ref);
536 } elseif ($modulepart == 'categorie' || $modulepart == 'category') {
537 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
538
539 if (!DolibarrApiAccess::$user->hasRight('categorie', 'lire')) {
540 throw new RestException(403);
541 }
542
543 $object = new Categorie($this->db);
544 $result = $object->fetch($id, $ref);
545 if (!$result) {
546 throw new RestException(404, 'Category not found');
547 }
548
549 $upload_dir = $conf->categorie->multidir_output[$object->entity].'/'.get_exdir($object->id, 2, 0, 0, $object, 'category').$object->id."/photos/".dol_sanitizeFileName($object->ref);
550 } elseif ($modulepart == 'ecm') {
551 throw new RestException(500, 'Modulepart Ecm not implemented yet.');
552 // require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
553
554 // if (!DolibarrApiAccess::$user->hasRight('ecm', 'read')) {
555 // throw new RestException(403);
556 // }
557
558 // // $object = new EcmDirectory($this->db);
559 // // $result = $object->fetch($ref);
560 // // if (!$result) {
561 // // throw new RestException(404, 'EcmDirectory not found');
562 // // }
563 // $upload_dir = $conf->ecm->dir_output;
564 // $type = 'all';
565 // $recursive = 0;
566 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
567 $modulepart = 'contrat';
568 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
569
570 $object = new Contrat($this->db);
571 $result = $object->fetch($id, $ref);
572 if (!$result) {
573 throw new RestException(404, 'Contract not found');
574 }
575
576 $upload_dir = $conf->contrat->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'contract');
577 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
578 $modulepart = 'project';
579 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
580
581 $object = new Project($this->db);
582 $result = $object->fetch($id, $ref);
583 if (!$result) {
584 throw new RestException(404, 'Project not found');
585 }
586
587 $upload_dir = $conf->projet->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'project');
588 } elseif ($modulepart == 'mrp') {
589 $modulepart = 'mrp';
590 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
591
592 $object = new Mo($this->db);
593 $result = $object->fetch($id, $ref);
594 if (!$result) {
595 throw new RestException(404, 'MO not found');
596 }
597
598 $upload_dir = $conf->mrp->dir_output . "/" . get_exdir(0, 0, 0, 1, $object, 'mrp');
599 } else {
600 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
601 }
602
603 $objectType = $modulepart;
604 if (! empty($object->id) && ! empty($object->table_element)) {
605 $objectType = $object->table_element;
606 }
607
608 $filearray = dol_dir_list($upload_dir, $type, $recursive, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1);
609 if (empty($filearray)) {
610 throw new RestException(404, 'Search for modulepart '.$modulepart.' with Id '.$object->id.(!empty($object->ref) ? ' or Ref '.$object->ref : '').' does not return any document.');
611 } else {
612 if (($object->id) > 0 && !empty($modulepart)) {
613 require_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php';
614 $ecmfile = new EcmFiles($this->db);
615 $result = $ecmfile->fetchAll('', '', 0, 0, array('t.src_object_type' => $objectType, 't.src_object_id' => $object->id));
616 if ($result < 0) {
617 throw new RestException(503, 'Error when retrieve ecm list : '.$this->db->lasterror());
618 } elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
619 $count = count($filearray);
620 for ($i = 0 ; $i < $count ; $i++) {
621 foreach ($ecmfile->lines as $line) {
622 if ($filearray[$i]['name'] == $line->filename) {
623 $filearray[$i] = array_merge($filearray[$i], (array) $line);
624 }
625 }
626 }
627 }
628 }
629 }
630
631 return $filearray;
632 }
633
634
643 /*
644 public function get($id) {
645 return array('note'=>'xxx');
646 }*/
647
648
678 public function post($filename, $modulepart, $ref = '', $subdir = '', $filecontent = '', $fileencoding = '', $overwriteifexists = 0, $createdirifnotexists = 1, $position = 0, $cover = '', $array_options = [])
679 {
680 global $conf;
681
682 $modulepartorig = $modulepart;
683
684 if (empty($modulepart)) {
685 throw new RestException(400, 'Modulepart not provided.');
686 }
687
688 $newfilecontent = '';
689 if (empty($fileencoding)) {
690 $newfilecontent = $filecontent;
691 }
692 if ($fileencoding == 'base64') {
693 $newfilecontent = base64_decode($filecontent);
694 }
695
696 $original_file = dol_sanitizeFileName($filename);
697
698 // Define $uploadir
699 $object = null;
700 $entity = DolibarrApiAccess::$user->entity;
701 if (empty($entity)) {
702 $entity = 1;
703 }
704
705 if ($ref) {
706 $tmpreldir = '';
707 $fetchbyid = false;
708
709 if ($modulepart == 'facture' || $modulepart == 'invoice') {
710 $modulepart = 'facture';
711
712 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
713 $object = new Facture($this->db);
714 } elseif ($modulepart == 'facture_fournisseur' || $modulepart == 'supplier_invoice') {
715 $modulepart = 'supplier_invoice';
716
717 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
718 $object = new FactureFournisseur($this->db);
719 } elseif ($modulepart == 'commande' || $modulepart == 'order') {
720 $modulepart = 'commande';
721
722 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
723 $object = new Commande($this->db);
724 } elseif ($modulepart == 'commande_fournisseur' || $modulepart == 'supplier_order') {
725 $modulepart = 'supplier_order';
726
727 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
728 $object = new CommandeFournisseur($this->db);
729 } elseif ($modulepart == 'projet' || $modulepart == 'project') {
730 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
731 $object = new Project($this->db);
732 } elseif ($modulepart == 'task' || $modulepart == 'project_task') {
733 $modulepart = 'project_task';
734
735 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
736 $object = new Task($this->db);
737
738 $task_result = $object->fetch(0, $ref);
739
740 // Fetching the tasks project is required because its out_dir might be a sub-directory of the project
741 if ($task_result > 0) {
742 $project_result = $object->fetchProject();
743
744 if ($project_result >= 0) {
745 $tmpreldir = dol_sanitizeFileName($object->project->ref).'/';
746 }
747 } else {
748 throw new RestException(500, 'Error while fetching Task '.$ref);
749 }
750 } elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') {
751 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
752 $object = new Product($this->db);
753 } elseif ($modulepart == 'expensereport') {
754 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
755 $object = new ExpenseReport($this->db);
756 } elseif ($modulepart == 'fichinter') {
757 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
758 $object = new Fichinter($this->db);
759 } elseif ($modulepart == 'adherent' || $modulepart == 'member') {
760 $modulepart = 'adherent';
761 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
762 $object = new Adherent($this->db);
763 } elseif ($modulepart == 'proposal' || $modulepart == 'propal' || $modulepart == 'propale') {
764 $modulepart = 'propale';
765 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
766 $object = new Propal($this->db);
767 } elseif ($modulepart == 'agenda' || $modulepart == 'action' || $modulepart == 'event') {
768 $modulepart = 'agenda';
769 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
770 $object = new ActionComm($this->db);
771 } elseif ($modulepart == 'contact' || $modulepart == 'socpeople') {
772 $modulepart = 'contact';
773 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
774 $object = new Contact($this->db);
775 $fetchbyid = true;
776 } elseif ($modulepart == 'contrat' || $modulepart == 'contract') {
777 $modulepart = 'contrat';
778 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
779 $object = new Contrat($this->db);
780 } elseif ($modulepart == 'mrp') {
781 $modulepart = 'mrp';
782 require_once DOL_DOCUMENT_ROOT . '/mrp/class/mo.class.php';
783 $object = new Mo($this->db);
784 } else {
785 // TODO Implement additional moduleparts
786 throw new RestException(500, 'Modulepart '.$modulepart.' not implemented yet.');
787 }
788
789 if (is_object($object)) {
790 if ($fetchbyid) {
791 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
792 $result = $object->fetch($ref);
793 } else {
794 $result = $object->fetch(0, $ref);
795 }
796
797 if ($result == 0) {
798 throw new RestException(404, "Object with ref '".$ref."' was not found.");
799 } elseif ($result < 0) {
800 throw new RestException(500, 'Error while fetching object: '.$object->error);
801 }
802 }
803
804 if (!($object->id > 0)) {
805 throw new RestException(404, 'The object '.$modulepart." with ref '".$ref."' was not found.");
806 }
807
808 // Special cases that need to use get_exdir to get real dir of object
809 // In future, all object should use this to define path of documents.
810 if ($modulepart == 'supplier_invoice') {
811 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
812 }
813
814 // Test on permissions
815 if ($modulepart != 'ecm') {
816 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref);
817 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, $ref, 'write');
818 $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
819 } else {
820 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
821 throw new RestException(403, 'Missing permission to upload files in ECM module');
822 }
823 $upload_dir = $conf->medias->multidir_output[$conf->entity];
824 }
825
826 if (empty($upload_dir) || $upload_dir == '/') {
827 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.');
828 }
829 } else {
830 if ($modulepart == 'invoice') {
831 $modulepart = 'facture';
832 }
833 if ($modulepart == 'member') {
834 $modulepart = 'adherent';
835 }
836
837 // Test on permissions
838 if ($modulepart != 'ecm') {
839 $relativefile = $subdir;
840 $tmp = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'write');
841 $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
842 } else {
843 if (!DolibarrApiAccess::$user->hasRight('ecm', 'upload')) {
844 throw new RestException(403, 'Missing permission to upload files in ECM module');
845 }
846 $upload_dir = $conf->medias->multidir_output[$conf->entity];
847 }
848
849 if (empty($upload_dir) || $upload_dir == '/') {
850 if (!empty($tmp['error'])) {
851 throw new RestException(403, 'Error returned by dol_check_secure_access_document: '.$tmp['error']);
852 } else {
853 throw new RestException(400, 'This value of modulepart ('.$modulepart.') is not allowed with this value of subdir ('.$relativefile.')');
854 }
855 }
856 }
857 // $original_file here is still value of filename without any dir.
858
859 $upload_dir = dol_sanitizePathName($upload_dir);
860
861 if (!empty($createdirifnotexists)) {
862 if (dol_mkdir($upload_dir) < 0) { // needed by products
863 throw new RestException(500, 'Error while trying to create directory '.$upload_dir);
864 }
865 }
866
867 $destfile = $upload_dir.'/'.$original_file;
868 $destfiletmp = DOL_DATA_ROOT.'/admin/temp/'.$original_file;
869 dol_delete_file($destfiletmp);
870 //var_dump($original_file);exit;
871
872 if (!dol_is_dir(dirname($destfile))) {
873 throw new RestException(400, 'Directory does not exists : '.dirname($destfile));
874 }
875
876 if (!$overwriteifexists && dol_is_file($destfile)) {
877 throw new RestException(400, "File with name '".$original_file."' already exists.");
878 }
879
880 // in case temporary directory admin/temp doesn't exist
881 if (!dol_is_dir(dirname($destfiletmp))) {
882 dol_mkdir(dirname($destfiletmp));
883 }
884
885 $fhandle = @fopen($destfiletmp, 'w');
886 if ($fhandle) {
887 $nbofbyteswrote = fwrite($fhandle, $newfilecontent);
888 fclose($fhandle);
889 dolChmod($destfiletmp);
890 } else {
891 throw new RestException(500, "Failed to open file '".$destfiletmp."' for write");
892 }
893
894 $disablevirusscan = 0;
895 $src_file = $destfiletmp;
896 $dest_file = $destfile;
897
898 // Security:
899 // If we need to make a virus scan
900 if (empty($disablevirusscan) && file_exists($src_file)) {
901 $checkvirusarray = dolCheckVirus($src_file, $dest_file);
902 if (count($checkvirusarray)) {
903 dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.implode(',', $checkvirusarray), LOG_WARNING);
904 throw new RestException(500, 'ErrorFileIsInfectedWithAVirus: '.implode(',', $checkvirusarray));
905 }
906 }
907
908 // Security:
909 // Disallow file with some extensions. We rename them.
910 // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code.
911 if (isAFileWithExecutableContent($dest_file) && !getDolGlobalString('MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED')) {
912 // $upload_dir ends with a slash, so be must be sure the medias dir to compare to ends with slash too.
913 $publicmediasdirwithslash = $conf->medias->multidir_output[$conf->entity];
914 if (!preg_match('/\/$/', $publicmediasdirwithslash)) {
915 $publicmediasdirwithslash .= '/';
916 }
917
918 if (strpos($upload_dir, $publicmediasdirwithslash) !== 0 || !getDolGlobalInt("MAIN_DOCUMENT_DISABLE_NOEXE_IN_MEDIAS_DIR")) { // We never add .noexe on files into media directory
919 $dest_file .= '.noexe';
920 }
921 }
922
923 // Security:
924 // We refuse cache files/dirs, upload using .. and pipes into filenames.
925 if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) {
926 dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING);
927 throw new RestException(500, "Refused to deliver file ".$src_file);
928 }
929
930 // Security:
931 // We refuse cache files/dirs, upload using .. and pipes into filenames.
932 if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) {
933 dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING);
934 throw new RestException(500, "Refused to deliver file ".$dest_file);
935 }
936
937 $moreinfo = array('note_private' => 'File uploaded using API /documents from IP '.getUserRemoteIP());
938 if (!empty($object) && is_object($object) && $object->id > 0) {
939 $moreinfo['src_object_type'] = $object->table_element;
940 $moreinfo['src_object_id'] = $object->id;
941 }
942 if (!empty($array_options)) {
943 $moreinfo = array_merge($moreinfo, ["array_options" => $array_options]);
944 }
945 if (!empty($position)) {
946 $moreinfo = array_merge($moreinfo, ["position" => $position]);
947 }
948 if (!empty($cover)) {
949 $moreinfo = array_merge($moreinfo, ["cover" => $cover]);
950 }
951
952 // Move the temporary file at its final emplacement
953 $result = dol_move($destfiletmp, $dest_file, '0', $overwriteifexists, 1, 1, $moreinfo);
954 if (!$result) {
955 throw new RestException(500, "Failed to move file into '".$dest_file."'");
956 }
957
958 return dol_basename($destfile);
959 }
960
976 public function delete($modulepart, $original_file)
977 {
978 global $conf, $langs;
979
980 if (empty($modulepart)) {
981 throw new RestException(400, 'bad value for parameter modulepart');
982 }
983 if (empty($original_file)) {
984 throw new RestException(400, 'bad value for parameter original_file');
985 }
986
987 //--- Finds and returns the document
988 $entity = $conf->entity;
989
990 // Special cases that need to use get_exdir to get real dir of object
991 // If future, all object should use this to define path of documents.
992 /*
993 $tmpreldir = '';
994 if ($modulepart == 'supplier_invoice') {
995 $tmpreldir = get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier');
996 }
997
998 $relativefile = $tmpreldir.dol_sanitizeFileName($object->ref); */
999 $relativefile = $original_file;
1000
1001 $check_access = dol_check_secure_access_document($modulepart, $relativefile, $entity, DolibarrApiAccess::$user, '', 'read');
1002 $accessallowed = $check_access['accessallowed'];
1003 $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals'];
1004 $original_file = $check_access['original_file'];
1005
1006 if (preg_match('/\.\./', $original_file) || preg_match('/[<>|]/', $original_file)) {
1007 throw new RestException(403);
1008 }
1009 if (!$accessallowed) {
1010 throw new RestException(403);
1011 }
1012
1013 $filename = basename($original_file);
1014 $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset
1015
1016 if (!file_exists($original_file_osencoded)) {
1017 dol_syslog("Try to download not found file ".$original_file_osencoded, LOG_WARNING);
1018 throw new RestException(404, 'File not found');
1019 }
1020
1021 if (@unlink($original_file_osencoded)) {
1022 return array(
1023 'success' => array(
1024 'code' => 200,
1025 'message' => 'Document deleted'
1026 )
1027 );
1028 }
1029
1030 throw new RestException(403);
1031 }
1032}
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
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.
post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='', $overwriteifexists=0, $createdirifnotexists=1, $position=0, $cover='', $array_options=[])
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 Trips and Expenses.
Class to manage suppliers invoices.
Class to manage invoices.
Class for KnowledgeRecord.
Class for Mo.
Definition mo.class.php:34
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.
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)
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79