dolibarr  21.0.0-alpha
website.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2007-2018 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es>
4  * Copyright (C) 2015 Florian Henry <florian.henry@open-concept.pro>
5  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
6  * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
7  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.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 
29 // Put here all includes required by your class file
30 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
31 //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
32 //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
33 
34 
38 class Website extends CommonObject
39 {
43  public $element = 'website';
44 
48  public $table_element = 'website';
49 
50  protected $childtablesoncascade = array();
51 
55  public $picto = 'globe';
56 
60  public $entity;
61 
65  public $ref;
66 
70  public $description;
71 
75  public $lang;
76 
80  public $otherlang;
81 
85  public $status;
86 
90  public $fk_default_home;
91 
95  public $fk_user_creat;
96 
100  public $fk_user_modif;
101 
105  public $virtualhost;
106 
110  public $use_manifest;
111 
115  public $position;
116 
120  public $name_template;
121 
122  const STATUS_DRAFT = 0;
123  const STATUS_VALIDATED = 1;
124 
125 
131  public function __construct(DoliDB $db)
132  {
133  $this->db = $db;
134 
135  $this->ismultientitymanaged = 1;
136  }
137 
145  public function create(User $user, $notrigger = 0)
146  {
147  global $conf, $langs;
148 
149  dol_syslog(__METHOD__, LOG_DEBUG);
150 
151  $error = 0;
152  $now = dol_now();
153 
154  // Clean parameters
155  if (isset($this->entity)) {
156  $this->entity = (int) $this->entity;
157  }
158  if (isset($this->ref)) {
159  $this->ref = trim($this->ref);
160  }
161  if (isset($this->description)) {
162  $this->description = trim($this->description);
163  }
164  if (isset($this->status)) {
165  $this->status = (int) $this->status;
166  }
167  if (empty($this->date_creation)) {
168  $this->date_creation = $now;
169  }
170  if (empty($this->date_modification)) {
171  $this->date_modification = $now;
172  }
173  // Remove spaces and be sure we have main language only
174  $this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en
175  $tmparray = explode(',', $this->otherlang);
176  if (is_array($tmparray)) {
177  foreach ($tmparray as $key => $val) {
178  // It possible we have empty val here if postparam WEBSITE_OTHERLANG is empty or set like this : 'en,,sv' or 'en,sv,'
179  if (empty(trim($val))) {
180  unset($tmparray[$key]);
181  continue;
182  }
183  $tmparray[$key] = preg_replace('/[_-].*$/', '', trim($val)); // en_US or en-US -> en
184  }
185  $this->otherlang = implode(',', $tmparray);
186  }
187 
188  // Check parameters
189  if (empty($this->entity)) {
190  $this->entity = $conf->entity;
191  }
192  if (empty($this->lang)) {
193  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("MainLanguage"));
194  return -1;
195  }
196 
197  // Insert request
198  $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'(';
199  $sql .= 'entity,';
200  $sql .= 'ref,';
201  $sql .= 'description,';
202  $sql .= 'lang,';
203  $sql .= 'otherlang,';
204  $sql .= 'status,';
205  $sql .= 'fk_default_home,';
206  $sql .= 'virtualhost,';
207  $sql .= 'fk_user_creat,';
208  $sql .= 'date_creation,';
209  $sql .= 'position,';
210  $sql .= 'tms';
211  $sql .= ') VALUES (';
212  $sql .= ' '.((empty($this->entity) && $this->entity != '0') ? 'NULL' : $this->entity).',';
213  $sql .= ' '.(!isset($this->ref) ? 'NULL' : "'".$this->db->escape($this->ref)."'").',';
214  $sql .= ' '.(!isset($this->description) ? 'NULL' : "'".$this->db->escape($this->description)."'").',';
215  $sql .= ' '.(!isset($this->lang) ? 'NULL' : "'".$this->db->escape($this->lang)."'").',';
216  $sql .= ' '.(!isset($this->otherlang) ? 'NULL' : "'".$this->db->escape($this->otherlang)."'").',';
217  $sql .= ' '.(!isset($this->status) ? '1' : $this->status).',';
218  $sql .= ' '.(!isset($this->fk_default_home) ? 'NULL' : $this->fk_default_home).',';
219  $sql .= ' '.(!isset($this->virtualhost) ? 'NULL' : "'".$this->db->escape($this->virtualhost)."'").",";
220  $sql .= ' '.(!isset($this->fk_user_creat) ? $user->id : $this->fk_user_creat).',';
221  $sql .= ' '.(!isset($this->date_creation) || dol_strlen($this->date_creation) == 0 ? 'NULL' : "'".$this->db->idate($this->date_creation)."'").",";
222  $sql .= ' '.((int) $this->position).",";
223  $sql .= ' '.(!isset($this->date_modification) || dol_strlen($this->date_modification) == 0 ? 'NULL' : "'".$this->db->idate($this->date_modification)."'");
224  $sql .= ')';
225 
226  $this->db->begin();
227 
228  $resql = $this->db->query($sql);
229  if (!$resql) {
230  $error++;
231  $this->errors[] = 'Error '.$this->db->lasterror();
232  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
233  }
234 
235  if (!$error) {
236  $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
237 
238  // Create a subdirectory for each language (except main language)
239  $tmplangarray = explode(',', $this->otherlang);
240  if (is_array($tmplangarray)) {
241  dol_mkdir($conf->website->dir_output.'/'.$this->ref);
242  foreach ($tmplangarray as $val) {
243  if (trim($val) == $this->lang) {
244  continue;
245  }
246  dol_mkdir($conf->website->dir_output.'/'.$this->ref.'/'.trim($val), DOL_DATA_ROOT);
247  }
248  }
249 
250  // Create subdirectory for images and js
251  dol_mkdir($conf->medias->multidir_output[$conf->entity].'/image/'.$this->ref, DOL_DATA_ROOT);
252  dol_mkdir($conf->medias->multidir_output[$conf->entity].'/js/'.$this->ref, DOL_DATA_ROOT);
253 
254  // Uncomment this and change WEBSITE to your own tag if you
255  // want this action to call a trigger.
256  // if (!$notrigger) {
257 
258  // // Call triggers
259  // $result = $this->call_trigger('WEBSITE_CREATE',$user);
260  // if ($result < 0) $error++;
261  // // End call triggers
262  // }
263  }
264 
265  if (!$error) {
266  $stringtodolibarrfile = "# Some properties for Dolibarr web site CMS\n";
267  $stringtodolibarrfile .= "param=value\n";
268  //print $conf->website->dir_output.'/'.$this->ref.'/.dolibarr';exit;
269  file_put_contents($conf->website->dir_output.'/'.$this->ref.'/.dolibarr', $stringtodolibarrfile);
270  }
271 
272  // Commit or rollback
273  if ($error) {
274  $this->db->rollback();
275  if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
276  return 0;
277  } else {
278  return -1 * $error;
279  }
280  } else {
281  $this->db->commit();
282 
283  return $this->id;
284  }
285  }
286 
294  public function fetch($id, $ref = null)
295  {
296  dol_syslog(__METHOD__, LOG_DEBUG);
297 
298  $sql = "SELECT";
299  $sql .= " t.rowid,";
300  $sql .= " t.entity,";
301  $sql .= " t.ref,";
302  $sql .= " t.position,";
303  $sql .= " t.description,";
304  $sql .= " t.lang,";
305  $sql .= " t.otherlang,";
306  $sql .= " t.status,";
307  $sql .= " t.fk_default_home,";
308  $sql .= " t.use_manifest,";
309  $sql .= " t.virtualhost,";
310  $sql .= " t.fk_user_creat,";
311  $sql .= " t.fk_user_modif,";
312  $sql .= " t.date_creation,";
313  $sql .= " t.tms as date_modification,";
314  $sql .= " t.name_template";
315  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
316  $sql .= " WHERE t.entity IN (".getEntity('website').")";
317  if (!empty($ref)) {
318  $sql .= " AND t.ref = '".$this->db->escape($ref)."'";
319  } else {
320  $sql .= " AND t.rowid = ".(int) $id;
321  }
322 
323  $resql = $this->db->query($sql);
324  if ($resql) {
325  $numrows = $this->db->num_rows($resql);
326  if ($numrows) {
327  $obj = $this->db->fetch_object($resql);
328 
329  $this->id = $obj->rowid;
330 
331  $this->entity = $obj->entity;
332  $this->ref = $obj->ref;
333  $this->position = $obj->position;
334  $this->description = $obj->description;
335  $this->lang = $obj->lang;
336  $this->otherlang = $obj->otherlang;
337  $this->status = $obj->status;
338  $this->fk_default_home = $obj->fk_default_home;
339  $this->virtualhost = $obj->virtualhost;
340  $this->use_manifest = $obj->use_manifest;
341  $this->fk_user_creat = $obj->fk_user_creat;
342  $this->fk_user_modif = $obj->fk_user_modif;
343  $this->date_creation = $this->db->jdate($obj->date_creation);
344  $this->date_modification = $this->db->jdate($obj->date_modification);
345  $this->name_template = $obj->name_template;
346  }
347  $this->db->free($resql);
348 
349  if ($numrows > 0) {
350  return 1;
351  } else {
352  return 0;
353  }
354  } else {
355  $this->errors[] = 'Error '.$this->db->lasterror();
356  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
357 
358  return -1;
359  }
360  }
361 
362 
374  public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
375  {
376  dol_syslog(__METHOD__, LOG_DEBUG);
377 
378  $records = array();
379 
380  $sql = "SELECT";
381  $sql .= " t.rowid,";
382  $sql .= " t.entity,";
383  $sql .= " t.ref,";
384  $sql .= " t.description,";
385  $sql .= " t.lang,";
386  $sql .= " t.otherlang,";
387  $sql .= " t.status,";
388  $sql .= " t.fk_default_home,";
389  $sql .= " t.virtualhost,";
390  $sql .= " t.fk_user_creat,";
391  $sql .= " t.fk_user_modif,";
392  $sql .= " t.date_creation,";
393  $sql .= " t.tms as date_modification";
394  $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t";
395  $sql .= " WHERE t.entity IN (".getEntity('website').")";
396 
397  // Manage filter
398  if (is_array($filter)) {
399  $sqlwhere = array();
400  if (count($filter) > 0) {
401  foreach ($filter as $key => $value) {
402  $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
403  }
404  }
405  if (count($sqlwhere) > 0) {
406  $sql .= ' AND '.implode(' '.$this->db->escape($filtermode).' ', $sqlwhere);
407  }
408 
409  $filter = '';
410  }
411 
412  // Manage filter
413  $errormessage = '';
414  $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
415  if ($errormessage) {
416  $this->errors[] = $errormessage;
417  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
418  return -1;
419  }
420 
421  if (!empty($sortfield)) {
422  $sql .= $this->db->order($sortfield, $sortorder);
423  }
424  if (!empty($limit)) {
425  $sql .= $this->db->plimit($limit, $offset);
426  }
427 
428  $resql = $this->db->query($sql);
429  if ($resql) {
430  $num = $this->db->num_rows($resql);
431 
432  while ($obj = $this->db->fetch_object($resql)) {
433  $record = new self($this->db);
434 
435  $record->id = $obj->rowid;
436 
437  $record->entity = $obj->entity;
438  $record->ref = $obj->ref;
439  $record->description = $obj->description;
440  $record->lang = $obj->lang;
441  $record->otherlang = $obj->otherlang;
442  $record->status = $obj->status;
443  $record->fk_default_home = $obj->fk_default_home;
444  $record->virtualhost = $obj->virtualhost;
445  $record->fk_user_creat = $obj->fk_user_creat;
446  $record->fk_user_modif = $obj->fk_user_modif;
447  $record->date_creation = $this->db->jdate($obj->date_creation);
448  $record->date_modification = $this->db->jdate($obj->date_modification);
449 
450  $records[$record->id] = $record;
451  }
452  $this->db->free($resql);
453 
454  return $records;
455  } else {
456  $this->errors[] = 'Error '.$this->db->lasterror();
457  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
458 
459  return -1;
460  }
461  }
462 
470  public function update(User $user, $notrigger = 0)
471  {
472  global $conf, $langs;
473 
474  $error = 0;
475 
476  dol_syslog(__METHOD__, LOG_DEBUG);
477 
478  // Clean parameters
479 
480  if (isset($this->entity)) {
481  $this->entity = (int) $this->entity;
482  }
483  if (isset($this->ref)) {
484  $this->ref = trim($this->ref);
485  }
486  if (isset($this->description)) {
487  $this->description = trim($this->description);
488  }
489  if (isset($this->status)) {
490  $this->status = (int) $this->status;
491  }
492 
493  // Remove spaces and be sure we have main language only
494  $this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en
495  $tmparray = explode(',', $this->otherlang);
496  if (is_array($tmparray)) {
497  foreach ($tmparray as $key => $val) {
498  // It possible we have empty val here if postparam WEBSITE_OTHERLANG is empty or set like this : 'en,,sv' or 'en,sv,'
499  if (empty(trim($val))) {
500  unset($tmparray[$key]);
501  continue;
502  }
503  $tmparray[$key] = preg_replace('/[_-].*$/', '', trim($val)); // en_US or en-US -> en
504  }
505  $this->otherlang = implode(',', $tmparray);
506  }
507  if (empty($this->lang)) {
508  $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("MainLanguage"));
509  return -1;
510  }
511 
512  // Check parameters
513  // Put here code to add a control on parameters values
514 
515  // Update request
516  $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET';
517  $sql .= ' entity = '.(isset($this->entity) ? $this->entity : "null").',';
518  $sql .= ' ref = '.(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").',';
519  $sql .= ' description = '.(isset($this->description) ? "'".$this->db->escape($this->description)."'" : "null").',';
520  $sql .= ' lang = '.(isset($this->lang) ? "'".$this->db->escape($this->lang)."'" : "null").',';
521  $sql .= ' otherlang = '.(isset($this->otherlang) ? "'".$this->db->escape($this->otherlang)."'" : "null").',';
522  $sql .= ' status = '.(isset($this->status) ? $this->status : "null").',';
523  $sql .= ' fk_default_home = '.(($this->fk_default_home > 0) ? $this->fk_default_home : "null").',';
524  $sql .= ' use_manifest = '.((int) $this->use_manifest).',';
525  $sql .= ' virtualhost = '.(($this->virtualhost != '') ? "'".$this->db->escape($this->virtualhost)."'" : "null").',';
526  $sql .= ' fk_user_modif = '.(!isset($this->fk_user_modif) ? $user->id : $this->fk_user_modif).',';
527  $sql .= ' date_creation = '.(!isset($this->date_creation) || dol_strlen($this->date_creation) != 0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').',';
528  $sql .= ' tms = '.(dol_strlen($this->date_modification) != 0 ? "'".$this->db->idate($this->date_modification)."'" : "'".$this->db->idate(dol_now())."'");
529  $sql .= ' WHERE rowid='.((int) $this->id);
530 
531  $this->db->begin();
532 
533  $resql = $this->db->query($sql);
534  if (!$resql) {
535  $error++;
536  $this->errors[] = 'Error '.$this->db->lasterror();
537  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
538  }
539 
540  if (!$error && !$notrigger) {
541  // Uncomment this and change MYOBJECT to your own tag if you
542  // want this action calls a trigger.
543 
544  // Create subdirectory per language
545  $tmplangarray = explode(',', $this->otherlang);
546  if (is_array($tmplangarray)) {
547  dol_mkdir($conf->website->dir_output.'/'.$this->ref);
548  foreach ($tmplangarray as $val) {
549  if (trim($val) == $this->lang) {
550  continue;
551  }
552  dol_mkdir($conf->website->dir_output.'/'.$this->ref.'/'.trim($val));
553  }
554  }
555 
557  //$result=$this->call_trigger('WEBSITE_MODIFY',$user);
558  //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
560  }
561 
562  // Commit or rollback
563  if ($error) {
564  $this->db->rollback();
565 
566  return -1 * $error;
567  } else {
568  $this->db->commit();
569 
570  return 1;
571  }
572  }
573 
581  public function delete(User $user, $notrigger = 0)
582  {
583  global $conf;
584 
585  dol_syslog(__METHOD__, LOG_DEBUG);
586 
587  $error = 0;
588 
589  $this->db->begin();
590 
591  if (!$error) {
592  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'categorie_website_page';
593  $sql .= ' WHERE fk_website_page IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'website_page WHERE fk_website = '.((int) $this->id).')';
594 
595  $resql = $this->db->query($sql);
596  if (!$resql) {
597  $error++;
598  $this->errors[] = 'Error '.$this->db->lasterror();
599  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
600  }
601  }
602 
603  if (!$error) {
604  $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'website_page';
605  $sql .= ' WHERE fk_website = '.((int) $this->id);
606 
607  $resql = $this->db->query($sql);
608  if (!$resql) {
609  $error++;
610  $this->errors[] = 'Error '.$this->db->lasterror();
611  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
612  }
613  }
614 
615  // Delete common code. This include execution of trigger.
616  $result = $this->deleteCommon($user, $notrigger);
617  if ($result <= 0) {
618  $error++;
619  }
620 
621  if (!$error && !empty($this->ref)) {
622  $pathofwebsite = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.$this->ref;
623 
624  dol_delete_dir_recursive($pathofwebsite);
625  }
626 
627  // Commit or rollback
628  if ($error) {
629  $this->db->rollback();
630 
631  return -1 * $error;
632  } else {
633  $this->db->commit();
634 
635  return 1;
636  }
637  }
638 
649  public function createFromClone($user, $fromid, $newref, $newlang = '')
650  {
651  global $conf, $langs;
652  global $dolibarr_main_data_root;
653 
654  $now = dol_now();
655  $error = 0;
656 
657  dol_syslog(__METHOD__, LOG_DEBUG);
658 
659  $newref = dol_sanitizeFileName($newref);
660 
661  if (empty($newref)) {
662  $this->error = 'ErrorBadParameter';
663  return -1;
664  }
665 
666  $object = new self($this->db);
667 
668  // Check no site with ref exists
669  if ($object->fetch(0, $newref) > 0) {
670  $this->error = 'ErrorNewRefIsAlreadyUsed';
671  return -1;
672  }
673 
674  $this->db->begin();
675 
676  // Load source object
677  $object->fetch($fromid);
678 
679  $oldidforhome = $object->fk_default_home;
680  $oldref = $object->ref;
681 
682  $pathofwebsiteold = $dolibarr_main_data_root.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.dol_sanitizeFileName($oldref);
683  $pathofwebsitenew = $dolibarr_main_data_root.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.dol_sanitizeFileName($newref);
684  dol_delete_dir_recursive($pathofwebsitenew);
685 
686  $fileindex = $pathofwebsitenew.'/index.php';
687 
688  // Reset some properties
689  unset($object->id);
690  unset($object->fk_user_creat);
691  unset($object->import_key);
692 
693  // Clear fields
694  $object->ref = $newref;
695  $object->fk_default_home = 0;
696  $object->virtualhost = '';
697  $object->date_creation = $now;
698  $object->fk_user_creat = $user->id;
699  $object->position = ((int) $object->position) + 1;
700  $object->status = self::STATUS_DRAFT;
701  if (empty($object->lang)) {
702  $object->lang = substr($langs->defaultlang, 0, 2); // Should not happen. Protection for corrupted site with no languages
703  }
704 
705  // Create clone
706  $object->context['createfromclone'] = 'createfromclone';
707  $result = $object->create($user);
708  if ($result < 0) {
709  $error++;
710  $this->error = $object->error;
711  $this->errors = $object->errors;
712  dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
713  }
714 
715  if (!$error) {
716  // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
717  dolCopyDir($pathofwebsiteold, $pathofwebsitenew, getDolGlobalString('MAIN_UMASK'), 0, [], 2);
718 
719  // Check symlink to medias and restore it if ko
720  $pathtomedias = DOL_DATA_ROOT.'/medias'; // Target
721  $pathtomediasinwebsite = $pathofwebsitenew.'/medias'; // Source / Link name
722  if (!is_link(dol_osencode($pathtomediasinwebsite))) {
723  dol_syslog("Create symlink for ".$pathtomedias." into name ".$pathtomediasinwebsite);
724  dol_mkdir(dirname($pathtomediasinwebsite)); // To be sure dir for website exists
725  $result = symlink($pathtomedias, $pathtomediasinwebsite);
726  }
727 
728  // Copy images and js dir
729  $pathofmediasjsold = DOL_DATA_ROOT.'/medias/js/'.$oldref;
730  $pathofmediasjsnew = DOL_DATA_ROOT.'/medias/js/'.$newref;
731  dolCopyDir($pathofmediasjsold, $pathofmediasjsnew, getDolGlobalString('MAIN_UMASK'), 0);
732 
733  $pathofmediasimageold = DOL_DATA_ROOT.'/medias/image/'.$oldref;
734  $pathofmediasimagenew = DOL_DATA_ROOT.'/medias/image/'.$newref;
735  dolCopyDir($pathofmediasimageold, $pathofmediasimagenew, getDolGlobalString('MAIN_UMASK'), 0);
736 
737  $newidforhome = 0;
738 
739  // Duplicate pages
740  $objectpages = new WebsitePage($this->db);
741  $listofpages = $objectpages->fetchAll($fromid);
742  foreach ($listofpages as $pageid => $objectpageold) {
743  // Delete old file
744  $filetplold = $pathofwebsitenew.'/page'.$pageid.'.tpl.php';
745  dol_delete_file($filetplold);
746 
747  // Create new file
748  $objectpagenew = $objectpageold->createFromClone($user, $pageid, $objectpageold->pageurl, '', 0, $object->id, 1);
749 
750  //print $pageid.' = '.$objectpageold->pageurl.' -> '.$objectpagenew->id.' = '.$objectpagenew->pageurl.'<br>';
751  if (is_object($objectpagenew) && $objectpagenew->pageurl) {
752  $filealias = $pathofwebsitenew.'/'.$objectpagenew->pageurl.'.php';
753  $filetplnew = $pathofwebsitenew.'/page'.$objectpagenew->id.'.tpl.php';
754 
755  // Save page alias
756  $result = dolSavePageAlias($filealias, $object, $objectpagenew);
757  if (!$result) {
758  setEventMessages('Failed to write file '.$filealias, null, 'errors');
759  }
760 
761  $result = dolSavePageContent($filetplnew, $object, $objectpagenew);
762  if (!$result) {
763  setEventMessages('Failed to write file '.$filetplnew, null, 'errors');
764  }
765 
766  if ($pageid == $oldidforhome) {
767  $newidforhome = $objectpagenew->id;
768  }
769  } else {
770  setEventMessages($objectpageold->error, $objectpageold->errors, 'errors');
771  $error++;
772  }
773  }
774  }
775 
776  if (!$error) {
777  // Restore id of home page
778  $object->fk_default_home = $newidforhome;
779  $res = $object->update($user);
780  if (!($res > 0)) {
781  $error++;
782  setEventMessages($object->error, $object->errors, 'errors');
783  }
784 
785  if (!$error) {
786  $filetpl = $pathofwebsitenew.'/page'.$newidforhome.'.tpl.php';
787  $filewrapper = $pathofwebsitenew.'/wrapper.php';
788 
789  // Re-generates the index.php page to be the home page, and re-generates the wrapper.php
790  //--------------------------------------------------------------------------------------
791  $result = dolSaveIndexPage($pathofwebsitenew, $fileindex, $filetpl, $filewrapper, $object);
792  }
793  }
794 
795  unset($object->context['createfromclone']);
796 
797  // End
798  if (!$error) {
799  $this->db->commit();
800 
801  return $object;
802  } else {
803  $this->db->rollback();
804 
805  return -1;
806  }
807  }
808 
820  public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $maxlen = 24, $morecss = '')
821  {
822  global $langs;
823 
824  $result = '';
825 
826  $label = '<u>'.$langs->trans("WebSite").'</u>';
827  $label .= '<br>';
828  $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref.'<br>';
829  $label .= '<b>'.$langs->trans('MainLanguage').':</b> '.$this->lang;
830 
831  $linkstart = '<a href="'.DOL_URL_ROOT.'/website/card.php?id='.$this->id.'"';
832  $linkstart .= ($notooltip ? '' : ' title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip'.($morecss ? ' '.$morecss : '').'"');
833  $linkstart .= '>';
834  $linkend = '</a>';
835 
836  $linkstart = $linkend = '';
837 
838  if ($withpicto) {
839  $result .= ($linkstart.img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? '' : 'class="classfortooltip"')).$linkend);
840  if ($withpicto != 2) {
841  $result .= ' ';
842  }
843  }
844  $result .= $linkstart.$this->ref.$linkend;
845  return $result;
846  }
847 
854  public function getLibStatut($mode = 0)
855  {
856  return $this->LibStatut($this->status, $mode);
857  }
858 
859  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
867  public function LibStatut($status, $mode = 0)
868  {
869  // phpcs:enable
870  global $langs;
871 
872  if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
873  global $langs;
874  //$langs->load("mymodule");
875  $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Offline');
876  $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Online');
877  $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Offline');
878  $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Online');
879  }
880 
881  $statusType = 'status5';
882  if ($status == self::STATUS_VALIDATED) {
883  $statusType = 'status4';
884  }
885 
886  return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
887  }
888 
889 
896  public function initAsSpecimen()
897  {
898  global $user;
899 
900  $this->id = 0;
901  $this->specimen = 1;
902  $this->entity = 1;
903  $this->ref = 'myspecimenwebsite';
904  $this->description = 'A specimen website';
905  $this->lang = 'en';
906  $this->otherlang = 'fr,es';
907  $this->status = 1;
908  $this->fk_default_home = 0;
909  $this->virtualhost = 'http://myvirtualhost';
910  $this->fk_user_creat = $user->id;
911  $this->fk_user_modif = $user->id;
912  $this->date_creation = dol_now();
913  $this->tms = dol_now();
914 
915  return 1;
916  }
917 
918 
924  public function exportWebSite()
925  {
926  global $conf, $mysoc;
927 
928  $website = $this;
929 
930  if (empty($website->id) || empty($website->ref)) {
931  setEventMessages("Website id or ref is not defined", null, 'errors');
932  return '';
933  }
934 
935  dol_syslog("Create temp dir ".$conf->website->dir_temp);
936  dol_mkdir($conf->website->dir_temp);
937  if (!is_writable($conf->website->dir_temp)) {
938  setEventMessages("Temporary dir ".$conf->website->dir_temp." is not writable", null, 'errors');
939  return '';
940  }
941 
942  $destdir = $conf->website->dir_temp.'/'.$website->ref;
943  dol_syslog("Clear temp dir ".$destdir);
944  $count = 0;
945  $countreallydeleted = 0;
946  $counttodelete = dol_delete_dir_recursive($destdir, $count, 1, 0, $countreallydeleted);
947  if ($counttodelete != $countreallydeleted) {
948  setEventMessages("Failed to clean temp directory ".$destdir, null, 'errors');
949  return '';
950  }
951 
952  $arrayreplacementinfilename = array();
953  $arrayreplacementincss = array();
954  $arrayreplacementincss['file=image/'.$website->ref.'/'] = "file=image/__WEBSITE_KEY__/";
955  $arrayreplacementincss['file=js/'.$website->ref.'/'] = "file=js/__WEBSITE_KEY__/";
956  $arrayreplacementincss['medias/image/'.$website->ref.'/'] = "medias/image/__WEBSITE_KEY__/";
957  $arrayreplacementincss['medias/js/'.$website->ref.'/'] = "medias/js/__WEBSITE_KEY__/";
958  if ($mysoc->logo_small) {
959  $arrayreplacementincss['file=logos%2Fthumbs%2F'.$mysoc->logo_small] = "file=logos%2Fthumbs%2F__LOGO_SMALL_KEY__";
960  }
961  if ($mysoc->logo_mini) {
962  $arrayreplacementincss['file=logos%2Fthumbs%2F'.$mysoc->logo_mini] = "file=logos%2Fthumbs%2F__LOGO_MINI_KEY__";
963  }
964  if ($mysoc->logo) {
965  $arrayreplacementincss['file=logos%2Fthumbs%2F'.$mysoc->logo] = "file=logos%2Fthumbs%2F__LOGO_KEY__";
966  }
967 
968  // Create output directories
969  dol_syslog("Create containers dir");
970  dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/containers');
971  dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/medias/image/websitekey');
972  dol_mkdir($conf->website->dir_temp.'/'.$website->ref.'/medias/js/websitekey');
973 
974  // Copy files into 'containers'
975  $srcdir = $conf->website->dir_output.'/'.$website->ref;
976  $destdir = $conf->website->dir_temp.'/'.$website->ref.'/containers';
977 
978  dol_syslog("Copy pages from ".$srcdir." into ".$destdir);
979  dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename, 2, array('old', 'back'), 1);
980 
981  // Copy file README.md and LICENSE from directory containers into directory root
982  if (dol_is_file($conf->website->dir_temp.'/'.$website->ref.'/containers/README.md')) {
983  dol_copy($conf->website->dir_temp.'/'.$website->ref.'/containers/README.md', $conf->website->dir_temp.'/'.$website->ref.'/README.md');
984  }
985  if (dol_is_file($conf->website->dir_temp.'/'.$website->ref.'/containers/LICENSE')) {
986  dol_copy($conf->website->dir_temp.'/'.$website->ref.'/containers/LICENSE', $conf->website->dir_temp.'/'.$website->ref.'/LICENSE');
987  }
988 
989  // Copy files into medias/image
990  $srcdir = DOL_DATA_ROOT.'/medias/image/'.$website->ref;
991  $destdir = $conf->website->dir_temp.'/'.$website->ref.'/medias/image/websitekey';
992 
993  dol_syslog("Copy content from ".$srcdir." into ".$destdir);
994  dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename);
995 
996  // Copy files into medias/js
997  $srcdir = DOL_DATA_ROOT.'/medias/js/'.$website->ref;
998  $destdir = $conf->website->dir_temp.'/'.$website->ref.'/medias/js/websitekey';
999 
1000  dol_syslog("Copy content from ".$srcdir." into ".$destdir);
1001  dolCopyDir($srcdir, $destdir, 0, 1, $arrayreplacementinfilename);
1002 
1003  // Make some replacement into some files
1004  $cssindestdir = $conf->website->dir_temp.'/'.$website->ref.'/containers/styles.css.php';
1005  if (dol_is_file($cssindestdir)) {
1006  dolReplaceInFile($cssindestdir, $arrayreplacementincss);
1007  }
1008 
1009  $htmldeaderindestdir = $conf->website->dir_temp.'/'.$website->ref.'/containers/htmlheader.html';
1010  if (dol_is_file($htmldeaderindestdir)) {
1011  dolReplaceInFile($htmldeaderindestdir, $arrayreplacementincss);
1012  }
1013 
1014  // Build the website_page.sql file
1015  $filesql = $conf->website->dir_temp.'/'.$website->ref.'/website_pages.sql';
1016  $fp = fopen($filesql, "w");
1017  if (empty($fp)) {
1018  setEventMessages("Failed to create file ".$filesql, null, 'errors');
1019  return '';
1020  }
1021 
1022  $objectpages = new WebsitePage($this->db);
1023  $listofpages = $objectpages->fetchAll($website->id);
1024 
1025 
1026  // Assign ->newid and ->newfk_page starting at 1.
1027  $i = 1;
1028  foreach ($listofpages as $pageid => $objectpageold) {
1029  $objectpageold->newid = $i;
1030  $i++;
1031  }
1032  $i = 1;
1033  foreach ($listofpages as $pageid => $objectpageold) {
1034  // Search newid
1035  $newfk_page = 0;
1036  foreach ($listofpages as $pageid2 => $objectpageold2) {
1037  if ($pageid2 == $objectpageold->fk_page) {
1038  $newfk_page = $objectpageold2->newid;
1039  break;
1040  }
1041  }
1042  $objectpageold->newfk_page = $newfk_page;
1043  $i++;
1044  }
1045 
1046  $line = '-- File generated by Dolibarr '.DOL_VERSION.' --;'."\n";
1047  $line .= "\n";
1048  fwrite($fp, $line);
1049 
1050  foreach ($listofpages as $pageid => $objectpageold) {
1051  $oldpageid = $objectpageold->id;
1052 
1053  $allaliases = $objectpageold->pageurl;
1054  $allaliases .= ($objectpageold->aliasalt ? ','.$objectpageold->aliasalt : '');
1055 
1056  if (!getDolGlobalInt('WEBSITE_EXPORT_KEEP_FILES_OF_PAGES')) {
1057  // We don't need to keep the PHP files of pages and aliases (they are regenerated at import) so we remove them.
1058  // Delete the pageX.tpl.php page
1059  dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/page'.$objectpageold->id.'.tpl.php', 0, 0, 0, null, false, 0);
1060  // Delete the alias page
1061  dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/'.$objectpageold->pageurl.'.php', 0, 0, 0, null, false, 0);
1062  dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/*/'.$objectpageold->pageurl.'.php', 0, 0, 0, null, false, 0);
1063  // Delete alternative alias pages
1064  $arrayofaliases = explode(',', $objectpageold->aliasalt);
1065  foreach ($arrayofaliases as $tmpaliasalt) {
1066  dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/'.trim($tmpaliasalt).'.php', 0, 0, 0, null, false, 0);
1067  dol_delete_file($conf->website->dir_temp.'/'.$website->ref.'/containers/*/'.trim($tmpaliasalt).'.php', 0, 0, 0, null, false, 0);
1068  }
1069  }
1070 
1071  // This comment syntax is important, it is parsed by import to get information on page ID and all aliases to regenerate
1072  $line = '-- Page ID '.$objectpageold->newid.'__+MAX_llx_website_page__ - Aliases '.$allaliases.' --;'; // newid start at 1, 2...
1073  $line .= "\n";
1074  fwrite($fp, $line);
1075 
1076  // Warning: We must keep llx_ here. It is a generic SQL.
1077  $line = 'INSERT INTO llx_website_page(rowid, fk_page, fk_website, pageurl, aliasalt, title, description, lang, image, keywords, status, date_creation, tms, import_key, grabbed_from, type_container, htmlheader, content, author_alias, allowed_in_frames)';
1078  $line .= " VALUES(";
1079  $line .= $objectpageold->newid."__+MAX_llx_website_page__, ";
1080  $line .= ($objectpageold->newfk_page ? $this->db->escape($objectpageold->newfk_page)."__+MAX_llx_website_page__" : "null").", ";
1081  $line .= "__WEBSITE_ID__, ";
1082  $line .= "'".$this->db->escape($objectpageold->pageurl)."', ";
1083  $line .= "'".$this->db->escape($objectpageold->aliasalt)."', ";
1084  $line .= "'".$this->db->escape($objectpageold->title)."', ";
1085  $line .= "'".$this->db->escape($objectpageold->description)."', ";
1086  $line .= "'".$this->db->escape($objectpageold->lang)."', ";
1087  $line .= "'".$this->db->escape($objectpageold->image)."', ";
1088  $line .= "'".$this->db->escape($objectpageold->keywords)."', ";
1089  $line .= "'".$this->db->escape($objectpageold->status)."', ";
1090  $line .= "'".$this->db->idate($objectpageold->date_creation)."', ";
1091  $line .= "'".$this->db->idate($objectpageold->date_modification)."', ";
1092  $line .= ($objectpageold->import_key ? "'".$this->db->escape($objectpageold->import_key)."'" : "null").", ";
1093  $line .= "'".$this->db->escape($objectpageold->grabbed_from)."', ";
1094  $line .= "'".$this->db->escape($objectpageold->type_container)."', ";
1095 
1096  // Make substitution with a generic path into htmlheader content
1097  $stringtoexport = $objectpageold->htmlheader;
1098  $stringtoexport = str_replace(array("\r\n", "\r", "\n"), "__N__", $stringtoexport);
1099  $stringtoexport = str_replace('file=image/'.$website->ref.'/', "file=image/__WEBSITE_KEY__/", $stringtoexport);
1100  $stringtoexport = str_replace('file=js/'.$website->ref.'/', "file=js/__WEBSITE_KEY__/", $stringtoexport);
1101  $stringtoexport = str_replace('medias/image/'.$website->ref.'/', "medias/image/__WEBSITE_KEY__/", $stringtoexport);
1102  $stringtoexport = str_replace('medias/js/'.$website->ref.'/', "medias/js/__WEBSITE_KEY__/", $stringtoexport);
1103 
1104  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo_small, "file=logos%2Fthumbs%2F__LOGO_SMALL_KEY__", $stringtoexport);
1105  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo_mini, "file=logos%2Fthumbs%2F__LOGO_MINI_KEY__", $stringtoexport);
1106  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo, "file=logos%2Fthumbs%2F__LOGO_KEY__", $stringtoexport);
1107  $line .= "'".$this->db->escape(str_replace(array("\r\n", "\r", "\n"), "__N__", $stringtoexport))."', "; // Replace \r \n to have record on 1 line
1108 
1109  // Make substitution with a generic path into page content
1110  $stringtoexport = $objectpageold->content;
1111  $stringtoexport = str_replace(array("\r\n", "\r", "\n"), "__N__", $stringtoexport);
1112  $stringtoexport = str_replace('file=image/'.$website->ref.'/', "file=image/__WEBSITE_KEY__/", $stringtoexport);
1113  $stringtoexport = str_replace('file=js/'.$website->ref.'/', "file=js/__WEBSITE_KEY__/", $stringtoexport);
1114  $stringtoexport = str_replace('medias/image/'.$website->ref.'/', "medias/image/__WEBSITE_KEY__/", $stringtoexport);
1115  $stringtoexport = str_replace('medias/js/'.$website->ref.'/', "medias/js/__WEBSITE_KEY__/", $stringtoexport);
1116  $stringtoexport = str_replace('"image/'.$website->ref.'/', '"image/__WEBSITE_KEY__/', $stringtoexport); // When we have a link src="image/websiteref/file.png" into html content
1117  $stringtoexport = str_replace('"/image/'.$website->ref.'/', '"/image/__WEBSITE_KEY__/', $stringtoexport); // When we have a link src="/image/websiteref/file.png" into html content
1118  $stringtoexport = str_replace('"js/'.$website->ref.'/', '"js/__WEBSITE_KEY__/', $stringtoexport);
1119  $stringtoexport = str_replace('"/js/'.$website->ref.'/', '"/js/__WEBSITE_KEY__/', $stringtoexport);
1120 
1121  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo_small, "file=logos%2Fthumbs%2F__LOGO_SMALL_KEY__", $stringtoexport);
1122  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo_mini, "file=logos%2Fthumbs%2F__LOGO_MINI_KEY__", $stringtoexport);
1123  $stringtoexport = str_replace('file=logos%2Fthumbs%2F'.$mysoc->logo, "file=logos%2Fthumbs%2F__LOGO_KEY__", $stringtoexport);
1124 
1125 
1126  $line .= "'".$this->db->escape($stringtoexport)."', "; // Replace \r \n to have record on 1 line
1127  $line .= "'".$this->db->escape($objectpageold->author_alias)."', ";
1128  $line .= (int) $objectpageold->allowed_in_frames;
1129  $line .= ");";
1130  $line .= "\n";
1131 
1132  fwrite($fp, $line);
1133 
1134  // Add line to update home page id during import
1135  //var_dump($this->fk_default_home.' - '.$objectpageold->id.' - '.$objectpageold->newid);exit;
1136  if ($this->fk_default_home > 0 && ($objectpageold->id == $this->fk_default_home) && ($objectpageold->newid > 0)) { // This is the page that is set as the home page
1137  // Warning: We must keep llx_ here. It is a generic SQL.
1138  $line = "UPDATE llx_website SET fk_default_home = ".($objectpageold->newid > 0 ? $this->db->escape($objectpageold->newid)."__+MAX_llx_website_page__" : "null")." WHERE rowid = __WEBSITE_ID__;";
1139  $line .= "\n";
1140  fwrite($fp, $line);
1141  }
1142 
1143  fwrite($fp, "\n");
1144  }
1145 
1146  $line = "\n-- For Dolibarr v14+ --;\n";
1147  $line .= "UPDATE llx_website SET lang = '".$this->db->escape($this->lang)."' WHERE rowid = __WEBSITE_ID__;\n";
1148  $line .= "UPDATE llx_website SET otherlang = '".$this->db->escape($this->otherlang)."' WHERE rowid = __WEBSITE_ID__;\n";
1149  $line .= "\n";
1150  fwrite($fp, $line);
1151 
1152  fclose($fp);
1153 
1154  dolChmod($filesql);
1155 
1156  // Build zip file
1157  $filedir = $conf->website->dir_temp.'/'.$website->ref.'/.';
1158  $fileglob = $conf->website->dir_temp.'/'.$website->ref.'/website_'.$website->ref.'-*.zip';
1159  $filename = $conf->website->dir_temp.'/'.$website->ref.'/website_'.$website->ref.'-'.dol_print_date(dol_now(), 'dayhourlog').'-V'.((float) DOL_VERSION).'.zip';
1160 
1161  dol_delete_file($fileglob, 0);
1162 
1163  $result = dol_compress_dir($filedir, $filename, 'zip');
1164 
1165  if ($result > 0) {
1166  return $filename;
1167  } else {
1168  global $errormsg;
1169  $this->error = $errormsg;
1170  return '';
1171  }
1172  }
1173 
1174 
1181  public function importWebSite($pathtofile)
1182  {
1183  global $conf, $mysoc;
1184 
1185  $error = 0;
1186 
1187  $pathtofile = dol_sanitizePathName($pathtofile);
1188  $object = $this;
1189  if (empty($object->ref)) {
1190  $this->error = 'Function importWebSite called on object not loaded (object->ref is empty)';
1191  return -2;
1192  }
1193 
1194  dol_delete_dir_recursive($conf->website->dir_temp."/".$object->ref);
1195  dol_mkdir($conf->website->dir_temp.'/'.$object->ref);
1196 
1197  $filename = basename($pathtofile);
1198  if (!preg_match('/^website_(.*)-(.*)$/', $filename, $reg)) {
1199  $this->errors[] = 'Bad format for filename '.$filename.'. Must be website_XXX-VERSION.';
1200  return -3;
1201  }
1202 
1203  $result = dol_uncompress($pathtofile, $conf->website->dir_temp.'/'.$object->ref);
1204 
1205  if (!empty($result['error'])) {
1206  $this->errors[] = 'Failed to unzip file '.$pathtofile.'.';
1207  return -4;
1208  }
1209 
1210  $arrayreplacement = array();
1211  $arrayreplacement['__WEBSITE_ID__'] = $object->id;
1212  $arrayreplacement['__WEBSITE_KEY__'] = $object->ref;
1213  $arrayreplacement['__N__'] = $this->db->escape("\n"); // Restore \n
1214  $arrayreplacement['__LOGO_SMALL_KEY__'] = $this->db->escape($mysoc->logo_small);
1215  $arrayreplacement['__LOGO_MINI_KEY__'] = $this->db->escape($mysoc->logo_mini);
1216  $arrayreplacement['__LOGO_KEY__'] = $this->db->escape($mysoc->logo);
1217 
1218 
1219  // Copy containers directory
1220  dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/containers', $conf->website->dir_output.'/'.$object->ref, 0, 1); // Overwrite if exists
1221 
1222  // Make replacement into css and htmlheader file
1223  $cssindestdir = $conf->website->dir_output.'/'.$object->ref.'/styles.css.php';
1224  $result = dolReplaceInFile($cssindestdir, $arrayreplacement);
1225 
1226  $htmldeaderindestdir = $conf->website->dir_output.'/'.$object->ref.'/htmlheader.html';
1227  $result = dolReplaceInFile($htmldeaderindestdir, $arrayreplacement);
1228 
1229  // Now generate the master.inc.php page
1230  $filemaster = $conf->website->dir_output.'/'.$object->ref.'/master.inc.php';
1231  $result = dolSaveMasterFile($filemaster);
1232  if (!$result) {
1233  $this->errors[] = 'Failed to write file '.$filemaster;
1234  $error++;
1235  }
1236 
1237  // Copy dir medias/image/websitekey
1238  if (dol_is_dir($conf->website->dir_temp.'/'.$object->ref.'/medias/image/websitekey')) {
1239  $result = dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/image/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/image/'.$object->ref, 0, 1);
1240  if ($result < 0) {
1241  $this->error = 'Failed to copy files into '.$conf->website->dir_output.'/'.$object->ref.'/medias/image/'.$object->ref.'.';
1242  dol_syslog($this->error, LOG_WARNING);
1243  $this->errors[] = $this->error;
1244  return -5;
1245  }
1246  }
1247 
1248  // Copy dir medias/js/websitekey
1249  if (dol_is_dir($conf->website->dir_temp.'/'.$object->ref.'/medias/js/websitekey')) {
1250  $result = dolCopyDir($conf->website->dir_temp.'/'.$object->ref.'/medias/js/websitekey', $conf->website->dir_output.'/'.$object->ref.'/medias/js/'.$object->ref, 0, 1);
1251  if ($result < 0) {
1252  $this->error = 'Failed to copy files into '.$conf->website->dir_output.'/'.$object->ref.'/medias/js/'.$object->ref.'.';
1253  dol_syslog($this->error, LOG_WARNING);
1254  $this->errors[] = $this->error;
1255  return -6;
1256  }
1257  }
1258 
1259  $sqlfile = $conf->website->dir_temp."/".$object->ref.'/website_pages.sql';
1260 
1261  $result = dolReplaceInFile($sqlfile, $arrayreplacement);
1262 
1263  $this->db->begin();
1264 
1265  // Search the $maxrowid because we need it later
1266  $sqlgetrowid = 'SELECT MAX(rowid) as max from '.MAIN_DB_PREFIX.'website_page';
1267  $resql = $this->db->query($sqlgetrowid);
1268  if ($resql) {
1269  $obj = $this->db->fetch_object($resql);
1270  $maxrowid = $obj->max;
1271  }
1272 
1273  // Load sql record
1274  $runsql = run_sql($sqlfile, 1, '', 0, '', 'none', 0, 1, 0, 0, 1); // The maxrowid of table is searched into this function two
1275  if ($runsql <= 0) {
1276  $this->errors[] = 'Failed to load sql file '.$sqlfile.' (ret='.((int) $runsql).')';
1277  $error++;
1278  }
1279 
1280  $objectpagestatic = new WebsitePage($this->db);
1281 
1282  // Regenerate the php files for pages
1283  $fp = fopen($sqlfile, "r");
1284  if ($fp) {
1285  while (!feof($fp)) {
1286  $reg = array();
1287 
1288  // Warning fgets with second parameter that is null or 0 hang.
1289  $buf = fgets($fp, 65000);
1290  $newid = 0;
1291 
1292  // Scan the line
1293  if (preg_match('/^-- Page ID (\d+)\s[^\s]+\s(\d+).*Aliases\s(.+)\s--;/i', $buf, $reg)) {
1294  // Example of line: "-- Page ID 179 -> 1__+MAX_llx_website_page__ - Aliases about-us --;"
1295  $oldid = (int) $reg[1];
1296  $newid = ((int) $reg[2] + $maxrowid);
1297  $aliasesarray = explode(',', $reg[3]);
1298 
1299  dol_syslog("In sql source file, we have the page ID ".$oldid." to replace with the new ID ".$newid.", and we must create the shortcut aliases: ".$reg[3]);
1300 
1301  //dol_move($conf->website->dir_output.'/'.$object->ref.'/page'.$oldid.'.tpl.php', $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php', 0, 1, 0, 0);
1302  } elseif (preg_match('/^-- Page ID (\d+).*Aliases\s(.*)\s--;/i', $buf, $reg)) {
1303  // Example of line: "-- Page ID 1__+MAX_llx_website_page__ - Aliases about-us --;"
1304  $newid = ((int) $reg[1] + $maxrowid);
1305  $aliasesarray = explode(',', $reg[2]);
1306 
1307  dol_syslog("In sql source file, we have the page with the new ID ".$newid.", and we must create the shortcut aliases: ".$reg[2]);
1308  }
1309 
1310  if ($newid) {
1311  $objectpagestatic->fetch($newid);
1312 
1313  // We regenerate the pageX.tpl.php
1314  $filetpl = $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php';
1315  $result = dolSavePageContent($filetpl, $object, $objectpagestatic);
1316  if (!$result) {
1317  $this->errors[] = 'Failed to write file '.basename($filetpl);
1318  $error++;
1319  }
1320 
1321  // Regenerate also the main alias + alternative aliases pages
1322  if (is_array($aliasesarray)) {
1323  foreach ($aliasesarray as $aliasshortcuttocreate) {
1324  if (trim($aliasshortcuttocreate)) {
1325  $filealias = $conf->website->dir_output.'/'.$object->ref.'/'.trim($aliasshortcuttocreate).'.php';
1326  $result = dolSavePageAlias($filealias, $object, $objectpagestatic);
1327  if (!$result) {
1328  $this->errors[] = 'Failed to write file '.basename($filealias);
1329  $error++;
1330  }
1331  }
1332  }
1333  }
1334  }
1335  }
1336  }
1337 
1338  // Read record of website that has been updated by the run_sql function previously called so we can get the
1339  // value of fk_default_home that is ID of home page
1340  $sql = "SELECT fk_default_home FROM ".MAIN_DB_PREFIX."website WHERE rowid = ".((int) $object->id);
1341  $resql = $this->db->query($sql);
1342  if ($resql) {
1343  $obj = $this->db->fetch_object($resql);
1344  if ($obj) {
1345  $object->fk_default_home = $obj->fk_default_home;
1346  } else {
1347  //$this->errors[] = 'Failed to get the Home page';
1348  //$error++;
1349  }
1350  }
1351 
1352  // Regenerate the index.php page to point to the new index page
1353  $pathofwebsite = $conf->website->dir_output.'/'.$object->ref;
1354  dolSaveIndexPage($pathofwebsite, $pathofwebsite.'/index.php', $pathofwebsite.'/page'.$object->fk_default_home.'.tpl.php', $pathofwebsite.'/wrapper.php', $object);
1355 
1356  //$this->initFilesStatus($pathofwebsite);
1357 
1358  if ($error) {
1359  $this->db->rollback();
1360  return -1;
1361  } else {
1362  $this->db->commit();
1363  return $object->id;
1364  }
1365  }
1366 
1373  public function rebuildWebSiteFiles()
1374  {
1375  global $conf;
1376 
1377  $error = 0;
1378 
1379  $object = $this;
1380  if (empty($object->ref)) {
1381  $this->error = 'Function rebuildWebSiteFiles called on object not loaded (object->ref is empty)';
1382  return -1;
1383  }
1384 
1385  $objectpagestatic = new WebsitePage($this->db);
1386 
1387  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."website_page WHERE fk_website = ".((int) $this->id);
1388 
1389  $resql = $this->db->query($sql);
1390  if (!$resql) {
1391  $this->error = $this->db->lasterror();
1392  return -1;
1393  }
1394 
1395  $num = $this->db->num_rows($resql);
1396 
1397  // Loop on each container/page
1398  $i = 0;
1399  while ($i < $num) {
1400  $obj = $this->db->fetch_object($resql);
1401 
1402  $newid = $obj->rowid;
1403 
1404  $objectpagestatic->fetch($newid);
1405 
1406  $aliasesarray = explode(',', $objectpagestatic->aliasalt);
1407 
1408  $filetpl = $conf->website->dir_output.'/'.$object->ref.'/page'.$newid.'.tpl.php';
1409  $result = dolSavePageContent($filetpl, $object, $objectpagestatic);
1410  if (!$result) {
1411  $this->errors[] = 'Failed to write file '.basename($filetpl);
1412  $error++;
1413  }
1414 
1415  // Add main alias to list of alternative aliases
1416  if (!empty($objectpagestatic->pageurl) && !in_array($objectpagestatic->pageurl, $aliasesarray)) {
1417  $aliasesarray[] = $objectpagestatic->pageurl;
1418  }
1419 
1420  // Regenerate also all aliases pages (pages with a natural name) by calling dolSavePageAlias()
1421  if (is_array($aliasesarray)) {
1422  foreach ($aliasesarray as $aliasshortcuttocreate) {
1423  if (trim($aliasshortcuttocreate)) {
1424  $filealias = $conf->website->dir_output.'/'.$object->ref.'/'.trim($aliasshortcuttocreate).'.php';
1425  $result = dolSavePageAlias($filealias, $object, $objectpagestatic); // This includes also a copy into sublanguage directories.
1426  if (!$result) {
1427  $this->errors[] = 'Failed to write file '.basename($filealias);
1428  $error++;
1429  }
1430  }
1431  }
1432  }
1433 
1434  $i++;
1435  }
1436 
1437  if (!$error) {
1438  // Save index.php and wrapper.php
1439  $pathofwebsite = $conf->website->dir_output.'/'.$object->ref;
1440  $fileindex = $pathofwebsite.'/index.php';
1441  $filetpl = '';
1442  if ($object->fk_default_home > 0) {
1443  $filetpl = $pathofwebsite.'/page'.$object->fk_default_home.'.tpl.php';
1444  }
1445  $filewrapper = $pathofwebsite.'/wrapper.php';
1446  dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper, $object); // This includes also a version of index.php into sublanguage directories
1447  }
1448 
1449  if ($error) {
1450  return -1;
1451  } else {
1452  return $num;
1453  }
1454  }
1455 
1461  public function isMultiLang()
1462  {
1463  return !empty($this->otherlang);
1464  }
1465 
1475  public function componentSelectLang($languagecodes, $weblangs, $morecss = '', $htmlname = '')
1476  {
1477  global $websitepagefile, $website;
1478 
1479  if (!is_object($weblangs)) {
1480  return 'ERROR componentSelectLang called with parameter $weblangs not defined';
1481  }
1482 
1483  $arrayofspecialmainlanguages = array(
1484  'en' => 'en_US',
1485  'sq' => 'sq_AL',
1486  'ar' => 'ar_SA',
1487  'eu' => 'eu_ES',
1488  'bn' => 'bn_DB',
1489  'bs' => 'bs_BA',
1490  'ca' => 'ca_ES',
1491  'zh' => 'zh_CN',
1492  'cs' => 'cs_CZ',
1493  'da' => 'da_DK',
1494  'et' => 'et_EE',
1495  'ka' => 'ka_GE',
1496  'el' => 'el_GR',
1497  'he' => 'he_IL',
1498  'kn' => 'kn_IN',
1499  'km' => 'km_KH',
1500  'ko' => 'ko_KR',
1501  'lo' => 'lo_LA',
1502  'nb' => 'nb_NO',
1503  'fa' => 'fa_IR',
1504  'sr' => 'sr_RS',
1505  'sl' => 'sl_SI',
1506  'uk' => 'uk_UA',
1507  'vi' => 'vi_VN'
1508  );
1509 
1510  // Load tmppage if we have $websitepagefile defined
1511  $tmppage = new WebsitePage($this->db);
1512 
1513  $pageid = 0;
1514  if (!empty($websitepagefile)) {
1515  $websitepagefileshort = basename($websitepagefile);
1516  if ($websitepagefileshort == 'index.php') {
1517  $pageid = $website->fk_default_home;
1518  } else {
1519  $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), $websitepagefileshort);
1520  }
1521  if ($pageid > 0) {
1522  $tmppage->fetch($pageid);
1523  }
1524  }
1525 
1526  // Fill $languagecodes array with existing translation, nothing if none
1527  if (!is_array($languagecodes) && $pageid > 0) {
1528  $languagecodes = array();
1529 
1530  $sql = "SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page";
1531  $sql .= " FROM ".MAIN_DB_PREFIX."website_page as wp";
1532  $sql .= " WHERE wp.fk_website = ".((int) $website->id);
1533  $sql .= " AND (wp.fk_page = ".((int) $pageid)." OR wp.rowid = ".((int) $pageid);
1534  if ($tmppage->fk_page > 0) {
1535  $sql .= " OR wp.fk_page = ".((int) $tmppage->fk_page)." OR wp.rowid = ".((int) $tmppage->fk_page);
1536  }
1537  $sql .= ")";
1538 
1539  $resql = $this->db->query($sql);
1540  if ($resql) {
1541  while ($obj = $this->db->fetch_object($resql)) {
1542  $newlang = $obj->lang;
1543  if ($obj->rowid == $pageid) {
1544  $newlang = $obj->lang;
1545  }
1546  if (!in_array($newlang, $languagecodes)) {
1547  $languagecodes[] = $newlang;
1548  }
1549  }
1550  }
1551  }
1552  // Now $languagecodes is always an array. Example array('en', 'fr', 'es');
1553 
1554  $languagecodeselected = substr($weblangs->defaultlang, 0, 2); // Because we must init with a value, but real value is the lang of main parent container
1555  if (!empty($websitepagefile)) {
1556  $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile));
1557  if ($pageid > 0) {
1558  $pagelang = substr($tmppage->lang, 0, 2);
1559  $languagecodeselected = substr($pagelang, 0, 2);
1560  if (!in_array($pagelang, $languagecodes)) {
1561  $languagecodes[] = $pagelang; // We add language code of page into combo list
1562  }
1563  }
1564  }
1565 
1566  $weblangs->load('languages');
1567  //var_dump($weblangs->defaultlang);
1568 
1569  $url = $_SERVER["REQUEST_URI"];
1570  $url = preg_replace('/(\?|&)l=([a-zA-Z_]*)/', '', $url); // We remove param l from url
1571  //$url = preg_replace('/(\?|&)lang=([a-zA-Z_]*)/', '', $url); // We remove param lang from url
1572  $url .= (preg_match('/\?/', $url) ? '&' : '?').'l=';
1573  if (!preg_match('/^\//', $url)) {
1574  $url = '/'.$url;
1575  }
1576 
1577  $HEIGHTOPTION = 40;
1578  $MAXHEIGHT = 4 * $HEIGHTOPTION;
1579  $nboflanguage = count($languagecodes);
1580 
1581  $out = '<!-- componentSelectLang'.$htmlname.' -->'."\n";
1582 
1583  $out .= '<style>';
1584  $out .= '.componentSelectLang'.$htmlname.':hover { height: '.min($MAXHEIGHT, ($HEIGHTOPTION * $nboflanguage)).'px; overflow-x: hidden; overflow-y: '.((($HEIGHTOPTION * $nboflanguage) > $MAXHEIGHT) ? ' scroll' : 'hidden').'; }'."\n";
1585  $out .= '.componentSelectLang'.$htmlname.' li { line-height: '.$HEIGHTOPTION.'px; }'."\n";
1586  $out .= '.componentSelectLang'.$htmlname.' {
1587  display: inline-block;
1588  padding: 0;
1589  height: '.$HEIGHTOPTION.'px;
1590  overflow: hidden;
1591  transition: all .3s ease;
1592  margin: 0 0 0 0;
1593  vertical-align: top;
1594  }
1595  .componentSelectLang'.$htmlname.':hover, .componentSelectLang'.$htmlname.':hover a { background-color: #fff; color: #000 !important; }
1596  ul.componentSelectLang'.$htmlname.' { width: 150px; }
1597  ul.componentSelectLang'.$htmlname.':hover .fa { visibility: hidden; }
1598  .componentSelectLang'.$htmlname.' a { text-decoration: none; width: 100%; }
1599  .componentSelectLang'.$htmlname.' li { display: block; padding: 0px 15px; margin-left: 0; margin-right: 0; }
1600  .componentSelectLang'.$htmlname.' li:hover { background-color: #EEE; }
1601  ';
1602  $out .= '</style>';
1603  $out .= '<ul class="componentSelectLang'.$htmlname.($morecss ? ' '.$morecss : '').'">';
1604 
1605  if ($languagecodeselected) {
1606  // Convert $languagecodeselected into a long language code
1607  if (strlen($languagecodeselected) == 2) {
1608  $languagecodeselected = (empty($arrayofspecialmainlanguages[$languagecodeselected]) ? $languagecodeselected.'_'.strtoupper($languagecodeselected) : $arrayofspecialmainlanguages[$languagecodeselected]);
1609  }
1610 
1611  $countrycode = strtolower(substr($languagecodeselected, -2));
1612  $label = $weblangs->trans("Language_".$languagecodeselected);
1613  if ($countrycode == 'us') {
1614  $label = preg_replace('/\s*\‍(.*\‍)/', '', $label);
1615  }
1616  $out .= '<li><a href="'.$url.substr($languagecodeselected, 0, 2).'"><img height="12px" src="/medias/image/common/flags/'.$countrycode.'.png" style="margin-right: 5px;"/><span class="websitecomponentlilang">'.$label.'</span>';
1617  $out .= '<span class="fa fa-caret-down" style="padding-left: 5px;" />';
1618  $out .= '</a></li>';
1619  }
1620  $i = 0;
1621  if (is_array($languagecodes)) {
1622  foreach ($languagecodes as $languagecode) {
1623  // Convert $languagecode into a long language code
1624  if (strlen($languagecode) == 2) {
1625  $languagecode = (empty($arrayofspecialmainlanguages[$languagecode]) ? $languagecode.'_'.strtoupper($languagecode) : $arrayofspecialmainlanguages[$languagecode]);
1626  }
1627 
1628  if ($languagecode == $languagecodeselected) {
1629  continue; // Already output
1630  }
1631 
1632  $countrycode = strtolower(substr($languagecode, -2));
1633  $label = $weblangs->trans("Language_".$languagecode);
1634  if ($countrycode == 'us') {
1635  $label = preg_replace('/\s*\‍(.*\‍)/', '', $label);
1636  }
1637  $out .= '<li><a href="'.$url.substr($languagecode, 0, 2).'"><img height="12px" src="/medias/image/common/flags/'.$countrycode.'.png" style="margin-right: 5px;"/><span class="websitecomponentlilang">'.$label.'</span>';
1638  if (empty($i) && empty($languagecodeselected)) {
1639  $out .= '<span class="fa fa-caret-down" style="padding-left: 5px;" />';
1640  }
1641  $out .= '</a></li>';
1642  $i++;
1643  }
1644  }
1645  $out .= '</ul>';
1646 
1647  return $out;
1648  }
1649 
1657  public function overwriteTemplate(string $pathtotmpzip, $exportPath = '')
1658  {
1659  global $conf;
1660 
1661  //$error = 0;
1662 
1663  $website = $this;
1664  if (empty($website->id) || empty($website->ref)) {
1665  setEventMessages("Website id or ref is not defined", null, 'errors');
1666  return -1;
1667  }
1668  if (empty($website->name_template) && empty($exportPath)) {
1669  setEventMessages("To export the website template into a directory of the server, the name of the directory/template must be provided.", null, 'errors');
1670  return -1;
1671  }
1672  if (!is_writable($conf->website->dir_temp)) {
1673  setEventMessages("Temporary dir ".$conf->website->dir_temp." is not writable", null, 'errors');
1674  return -1;
1675  }
1676 
1677  // Replace modified files into the doctemplates directory.
1678  if (getDolGlobalString('WEBSITE_ALLOW_OVERWRITE_GIT_SOURCE')) {
1679  // If the user has not specified a path
1680  if (empty($exportPath)) {
1681  $destdirrel = 'install/doctemplates/websites/'.$website->name_template;
1682  $destdir = DOL_DOCUMENT_ROOT.'/'.$destdirrel;
1683  } else {
1684  $exportPath = rtrim($exportPath, '/');
1685  if (strpos($exportPath, '..') !== false) {
1686  setEventMessages("Invalid path.", null, 'errors');
1687  return -1;
1688  }
1689  // if path start with / (absolute path)
1690  if (strpos($exportPath, '/') === 0 || preg_match('/^[a-zA-Z]:/', $exportPath)) {
1691  if (!is_dir($exportPath)) {
1692  setEventMessages("The specified absolute path does not exist.", null, 'errors');
1693  return -1;
1694  }
1695 
1696  if (!is_writable($exportPath)) {
1697  setEventMessages("The specified absolute path is not writable.", null, 'errors');
1698  return -1;
1699  }
1700  $destdirrel = $exportPath;
1701  $destdir = $exportPath;
1702  } else {
1703  // relatif path
1704  $destdirrel = 'install/doctemplates/websites/'.$exportPath;
1705  $destdir = DOL_DOCUMENT_ROOT.'/'.$destdirrel;
1706  }
1707  }
1708  }
1709 
1710  dol_mkdir($destdir);
1711 
1712  if (!is_writable($destdir)) {
1713  setEventMessages("The specified path ".$destdir." is not writable.", null, 'errors');
1714  return -1;
1715  }
1716 
1717  // Export on target sources
1718  $resultarray = dol_uncompress($pathtotmpzip, $destdir);
1719 
1720  // Remove the file README and LICENSE from the $destdir/containers
1721  if (dol_is_file($destdir.'/containers/README.md')) {
1722  dol_move($destdir.'/containers/README.md', $destdir.'/README.md', '0', 1, 0, 0);
1723  }
1724  if (dol_is_file($destdir.'/containers/LICENSE')) {
1725  dol_move($destdir.'/containers/LICENSE', $destdir.'/LICENSE', '0', 1, 0, 0);
1726  }
1727  /*
1728  if (empty($exportPath)) {
1729  dol_delete_file($destdir.'/containers/README.md');
1730  dol_delete_file($destdir.'/containers/LICENSE');
1731  }
1732  */
1733 
1734  // Remove non required files (will be re-generated during the import)
1735  dol_delete_file($destdir.'/containers/index.php');
1736  dol_delete_file($destdir.'/containers/master.inc.php');
1737 
1738  // Now we remove the flag o+x on files
1739  // TODO
1740 
1741  if (!empty($resultarray)) {
1742  setEventMessages("Error, failed to unzip the export into target dir ".$destdir.": ".implode(',', $resultarray), null, 'errors');
1743  } else {
1744  setEventMessages("Website content written into ".$destdirrel, null, 'mesgs');
1745  }
1746 
1747  header("Location: ".$_SERVER["PHP_SELF"].'?website='.$website->ref);
1748  exit();
1749  }
1750 
1756  protected function extractNumberFromFilename($filename)
1757  {
1758  $matches = [];
1759  if (preg_match('/page(\d+)\.tpl\.php/', $filename, $matches)) {
1760  return (int) $matches[1];
1761  }
1762  return -1;
1763  }
1764 
1770  public function setTemplateName($name_template)
1771  {
1772  $sql = "UPDATE ".$this->db->prefix()."website SET";
1773  $sql .= " name_template = '".$this->db->escape($name_template)."'";
1774  $sql .= " WHERE rowid = ".(int) $this->id;
1775  $result = $this->db->query($sql);
1776 
1777  if ($result) {
1778  $this->db->commit();
1779  return 1;
1780  } else {
1781  $this->db->rollback();
1782  return -1;
1783  }
1784  }
1785 
1791  public function checkPreviousState($pathname)
1792  {
1793  if (!file_exists($pathname)) {
1794  if (touch($pathname)) {
1795  dolChmod($pathname, '0664');
1796  }
1797  return [];
1798  }
1799  return unserialize(file_get_contents($pathname));
1800  }
1801 
1802 
1809  public function saveState($etat, $pathname)
1810  {
1811  return file_put_contents($pathname, serialize($etat));
1812  }
1813 
1821  public function compareFichierModifie($dossierSource, $dossierDestination, $fichierModifie)
1822  {
1823 
1824  $fichiersSource = [];
1825  $fichiersDestination = [];
1826 
1827  $fichierWithNoPage = [];
1828  $fichierWithNoPageInDest = [];
1829 
1830  // Filter source files
1831  foreach (dol_dir_list($dossierSource, "files") as $file) {
1832  if (preg_match('/^page\d+/', $file['name']) && !str_contains($file['name'], '.old')) {
1833  $fichiersSource[] = $file;
1834  } else {
1835  $fichierWithNoPage[] = $file;
1836  }
1837  }
1838 
1839  // Filter destination files
1840  foreach (dol_dir_list($dossierDestination, "all", 1) as $file) {
1841  if (preg_match('/^page\d+/', $file['name']) && !str_contains($file['name'], '.old')) {
1842  $fichiersDestination[] = $file;
1843  } else {
1844  $fichierWithNoPageInDest[] = $file;
1845  }
1846  }
1847 
1848  // find index source and search it in folder destination
1849  $numOfPageSource = 0;
1850  foreach ($fichiersSource as $index => $file) {
1851  if ($file['name'] == basename($fichierModifie['fullname'])) {
1852  $numOfPageSource = $this->extractNumberFromFilename($file['name']);
1853  break;
1854  }
1855  }
1856 
1857  //search numPage where was declared
1858  $filesFound = array();
1859  foreach ($fichierWithNoPage as $filesource) {
1860  $fileContent = file_get_contents($filesource['fullname']);
1861  if (strpos($fileContent, "require './page".$numOfPageSource.".tpl.php'") !== false) {
1862  $filesFound = $filesource;
1863  break;
1864  }
1865  }
1866  // find file with same name and extract num page in destination folder
1867  $numPagesFound = '';
1868  foreach ($fichierWithNoPageInDest as $filedest) {
1869  if ($filedest['name'] === $filesFound['name']) {
1870  $fileContent = file_get_contents($filedest['fullname']);
1871  if (preg_match("/page\d+\.tpl\.php/", $fileContent, $matches)) {
1872  $numPagesFound = $matches[0];
1873  break;
1874  }
1875  }
1876  }
1877  //search file with the number of pages found
1878  $fileNeeded = array();
1879  foreach ($fichiersDestination as $index => $file) {
1880  if ($file['name'] == $numPagesFound) {
1881  $fileNeeded = $file;
1882  break;
1883  }
1884  }
1885 
1886  if (isset($fileNeeded)) {
1887  $sourceContent = file_get_contents($fichierModifie['fullname']);
1888  if (file_exists($fileNeeded['fullname'])) {
1889  $destContent = file_get_contents($fileNeeded['fullname']);
1890 
1891  $numOfPageDest = $this->extractNumberFromFilename($fileNeeded['name']);
1892  $differences = $this->showDifferences($destContent, $sourceContent, array($numOfPageDest,$numOfPageSource));
1893  $differences['file_destination'] = $fileNeeded;
1894  } else {
1895  $differences = array();
1896  }
1897  return $differences;
1898  }
1899  return array();
1900  }
1901 
1907  private function normalizeString($str)
1908  {
1909  $str = str_replace("\r\n", "\n", $str);
1910  $str = str_replace("\r", "\n", $str);
1911  return $str;
1912  }
1913 
1921  protected function showDifferences($str1, $str2, $exceptNumPge = array())
1922  {
1923  $diff = array();
1924  $str1 = $this->normalizeString($str1);
1925  $str2 = $this->normalizeString($str2);
1926 
1927  $lines1 = explode("\n", $str1);
1928  $lines2 = explode("\n", $str2);
1929 
1930  $linesShouldChange = array();
1931  $linesShouldNotChange = array();
1932  $linefound = array();
1933  $countNumPage = count($exceptNumPge);
1934 
1935  for ($i = 0;$i < $countNumPage; $i++) {
1936  $linefound[$i] = array();
1937  $linefound[$i]['meta'] = '/content="' . preg_quote($exceptNumPge[$i], '/') . '" \/>/';
1938  $linefound[$i]['output'] = '/dolWebsiteOutput\‍(\$tmp, "html", ' . preg_quote($exceptNumPge[$i], '/') . '\‍);/';
1939  }
1940 
1941  if (isset($linefound[1])) {
1942  $maxLines = max(count($lines1), count($lines2));
1943  for ($lineNum = 0; $lineNum < $maxLines; $lineNum++) {
1944  $lineContent1 = $lines1[$lineNum] ?? '';
1945  $lineContent2 = $lines2[$lineNum] ?? '';
1946  if (preg_match($linefound[0]['output'], $lineContent1)) {
1947  $linesShouldChange[] = $lineContent1;
1948  }
1949  if (preg_match($linefound[0]['meta'], $lineContent1)) {
1950  $linesShouldChange[] = $lineContent1;
1951  }
1952  if (preg_match($linefound[1]['output'], $lineContent2)) {
1953  $linesShouldNotChange[] = $lineContent2;
1954  }
1955  if (preg_match($linefound[1]['meta'], $lineContent2)) {
1956  $linesShouldNotChange[] = $lineContent2;
1957  }
1958  if ($lineContent1 !== $lineContent2) {
1959  if (isset($lines1[$lineNum]) && !isset($lines2[$lineNum])) {
1960  // Ligne deleted de la source
1961  $diff["Supprimée à la ligne " . ($lineNum + 1)] = $lineContent1;
1962  } elseif (!isset($lines1[$lineNum]) && isset($lines2[$lineNum])) {
1963  // Nouvelle ligne added dans la destination
1964  $diff["Ajoutée à la ligne " . ($lineNum + 1)] = $lineContent2;
1965  } else {
1966  // Différence found it
1967  $diff["Modifiée à la ligne " . ($lineNum + 1)] = $lineContent2;
1968  }
1969  }
1970  }
1971  }
1972 
1973 
1974  if (empty($linesShouldChange)) {
1975  $linesShouldChange[0] = '<meta name="dolibarr:pageid" content="'.$exceptNumPge[0].'" />';
1976  $linesShouldChange[1] = '$tmp = ob_get_contents(); ob_end_clean(); dolWebsiteOutput($tmp, "html", '.$exceptNumPge[0].');';
1977  }
1978 
1979  $replacementMapping = array();
1980  if (!empty($linesShouldNotChange)) {
1981  $i = 0;
1982  foreach ($linesShouldNotChange as $numLigne => $ligneRemplacement) {
1983  if (isset($linesShouldChange[$numLigne])) {
1984  $replacementMapping[$ligneRemplacement] = $linesShouldChange[$numLigne];
1985  } else {
1986  $replacementMapping[$ligneRemplacement] = $linesShouldChange[$i];
1987  }
1988  $i++;
1989  }
1990  $diff['lignes_dont_change'] = $replacementMapping;
1991  }
1992  // search path of image and replace it with the correct path
1993  $pattern = '/medias\/image\/'.preg_quote($this->ref, '/').'\/([^\'"\s]+)/';
1994 
1995  foreach ($diff as $key => $value) {
1996  // Ensure the value is a string
1997  if (is_string($value)) {
1998  if (preg_match($pattern, $value)) {
1999  $newValue = preg_replace($pattern, 'medias/image/'.$this->name_template.'/$1', $value);
2000  $diff[$key] = $newValue;
2001  }
2002  }
2003  }
2004  return $diff;
2005  }
2006 
2014  protected function replaceLineUsingNum($inplaceFile, $differences)
2015  {
2016  if (file_exists($inplaceFile)) {
2017  dolChmod($inplaceFile, '0664');
2018  }
2019  if (!is_writable($inplaceFile)) {
2020  return -2;
2021  }
2022 
2023  unset($differences['file_destination']);
2024  $contentDest = file($inplaceFile, FILE_IGNORE_NEW_LINES);
2025  foreach ($differences as $key => $ligneSource) {
2026  $matches = array();
2027  if (preg_match('/(Ajoutée|Modifiée) à la ligne (\d+)/', $key, $matches)) {
2028  $typeModification = $matches[1];
2029  $numLigne = (int) $matches[2] - 1;
2030 
2031  if ($typeModification === 'Ajoutée') {
2032  array_splice($contentDest, $numLigne, 0, $ligneSource);
2033  } elseif ($typeModification === 'Modifiée') {
2034  $contentDest[$numLigne] = $ligneSource;
2035  }
2036  } elseif (preg_match('/Supprimée à la ligne (\d+)/', $key, $matches)) {
2037  $numLigne = (int) $matches[1] - 1;
2038  unset($contentDest[$numLigne]);
2039  }
2040  }
2041  // Reindex the table keys
2042  $contentDest = array_values($contentDest);
2043  $stringreplacement = implode("\n", $contentDest);
2044  file_put_contents($inplaceFile, $stringreplacement);
2045  foreach ($differences['lignes_dont_change'] as $linechanged => $line) {
2046  if (in_array($linechanged, $contentDest)) {
2047  dolReplaceInFile($inplaceFile, array($linechanged => $line));
2048  }
2049  }
2050 
2051  return 0;
2052  }
2053 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition: security.php:624
run_sql($sqlfile, $silent=1, $entity=0, $usesavepoint=1, $handler='', $okerror='default', $linelengthlimit=32768, $nocommentremoval=0, $offsetforchartofaccount=0, $colspan=0, $onlysqltoimportwebsite=0, $database='')
Launch a sql file.
Definition: admin.lib.php:170
print $object position
Definition: edit.php:195
$object ref
Definition: info.php:79
Parent class of all other business classes (invoices, contracts, proposals, orders,...
deleteCommon(User $user, $notrigger=0, $forcechilddeletion=0)
Delete object in database.
Class to manage Dolibarr database access.
Class to manage Dolibarr users.
Definition: user.class.php:50
Class Website.
isMultiLang()
Return if web site is a multilanguage web site.
setTemplateName($name_template)
update name_template in table after import template
create(User $user, $notrigger=0)
Create object into database.
rebuildWebSiteFiles()
Rebuild all files of all the pages/containers of a website.
exportWebSite()
Generate a zip with all data of web site.
replaceLineUsingNum($inplaceFile, $differences)
Replace line by line in file using numbers of the lines.
initAsSpecimen()
Initialise object with example values Id must be 0 if object instance is a specimen.
componentSelectLang($languagecodes, $weblangs, $morecss='', $htmlname='')
Component to select language inside a container (Full CSS Only)
extractNumberFromFilename($filename)
extract num of page
createFromClone($user, $fromid, $newref, $newlang='')
Load a website its id and create a new one in database.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND')
Load all object in memory ($this->records) from the database.
overwriteTemplate(string $pathtotmpzip, $exportPath='')
Overite template by copying all files.
__construct(DoliDB $db)
Constructor.
saveState($etat, $pathname)
Save state for File.
getLibStatut($mode=0)
Return the label of the status.
LibStatut($status, $mode=0)
Return the label of a given status.
getNomUrl($withpicto=0, $option='', $notooltip=0, $maxlen=24, $morecss='')
Return a link to the user card (with optionally the picto) Use this->id,this->lastname,...
normalizeString($str)
Remove spaces in string.
update(User $user, $notrigger=0)
Update object into database.
fetch($id, $ref=null)
Load object in memory from the database.
compareFichierModifie($dossierSource, $dossierDestination, $fichierModifie)
Compare two files has not same name but same content.
showDifferences($str1, $str2, $exceptNumPge=array())
show difference between to string
checkPreviousState($pathname)
check previous state for file
Class Websitepage.
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:751
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1620
dol_copy($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=0)
Copy a file to another file.
Definition: files.lib.php:767
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.
Definition: files.lib.php:1469
dol_uncompress($inputfile, $outputdir)
Uncompress a file.
Definition: files.lib.php:2463
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array())
Move a file into another name.
Definition: files.lib.php:1011
dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null, $excludesubdir=0, $excludefileext=null, $excludearchivefiles=0)
Copy a dir to another dir.
Definition: files.lib.php:896
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:519
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.
Definition: files.lib.php:489
dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask='0', $indexdatabase=0, $arrayreplacementisregex=0)
Make replacement of strings into a file.
Definition: files.lib.php:677
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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)
div float
Unit price before taxes.
Definition: style.css.php:963
dolSaveMasterFile($filemaster)
Save content of a page on disk.
dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper, $object=null)
Save content of the index.php and/or the wrapper.php page.
dolSavePageAlias($filealias, $object, $objectpage)
Save an alias page on disk (A page that include the reference page).
dolSavePageContent($filetpl, Website $object, WebsitePage $objectpage, $backupold=0)
Save content of a page on disk (page name is generally ID_of_page.php).