| Total Complexity | 281 |
| Total Lines | 1436 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like Utils often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Utils, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 39 | class Utils |
||
| 40 | { |
||
| 41 | /** |
||
| 42 | * @var DoliDB Database handler |
||
| 43 | */ |
||
| 44 | public $db; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * @var string Error message |
||
| 48 | * @see $errors |
||
| 49 | */ |
||
| 50 | public $error; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * @var string[] Array of error messages |
||
| 54 | */ |
||
| 55 | public $errors; |
||
| 56 | |||
| 57 | /** |
||
| 58 | * @var string Used by Cron method to return message |
||
| 59 | */ |
||
| 60 | public $output; |
||
| 61 | |||
| 62 | /** |
||
| 63 | * @var array{commandbackuplastdone:string,commandbackuptorun:string} Used by Cron method to return data |
||
| 64 | */ |
||
| 65 | public $result; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Constructor |
||
| 69 | * |
||
| 70 | * @param DoliDB $db Database handler |
||
| 71 | */ |
||
| 72 | public function __construct($db) |
||
| 73 | { |
||
| 74 | $this->db = $db; |
||
| 75 | } |
||
| 76 | |||
| 77 | |||
| 78 | /** |
||
| 79 | * Purge files into directory of data files. |
||
| 80 | * CAN BE A CRON TASK |
||
| 81 | * |
||
| 82 | * @param string $choices Choice of purge mode ('tempfiles', 'tempfilesold' to purge temp older than $nbsecondsold seconds, 'logfiles', or mix of this). Note that 'allfiles' is also possible but very dangerous. |
||
| 83 | * @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold', or deletion of file if $choice is 'allfiles' |
||
| 84 | * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) |
||
| 85 | */ |
||
| 86 | public function purgeFiles($choices = 'tempfilesold+logfiles', $nbsecondsold = 86400) |
||
| 87 | { |
||
| 88 | global $conf, $langs, $user; |
||
| 89 | global $dolibarr_main_data_root; |
||
| 90 | |||
| 91 | $langs->load("admin"); |
||
| 92 | |||
| 93 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; |
||
| 94 | |||
| 95 | if (empty($choices)) { |
||
| 96 | $choices = 'tempfilesold+logfiles'; |
||
| 97 | } |
||
| 98 | if ($choices == 'allfiles' && $nbsecondsold > 0) { |
||
| 99 | $choices = 'allfilesold'; |
||
| 100 | } |
||
| 101 | |||
| 102 | dol_syslog("Utils::purgeFiles choice=" . $choices, LOG_DEBUG); |
||
| 103 | |||
| 104 | // For dangerous action, we check the user is admin |
||
| 105 | if (in_array($choices, array('allfiles', 'allfilesold'))) { |
||
| 106 | if (empty($user->admin)) { |
||
| 107 | $this->output = 'Error: to erase data files, user running the batch (currently ' . $user->login . ') must be an admin user'; |
||
| 108 | return 1; |
||
| 109 | } |
||
| 110 | } |
||
| 111 | |||
| 112 | $count = 0; |
||
| 113 | $countdeleted = 0; |
||
| 114 | $counterror = 0; |
||
| 115 | $filelog = ''; |
||
| 116 | |||
| 117 | $choicesarray = preg_split('/[\+,]/', $choices); |
||
| 118 | foreach ($choicesarray as $choice) { |
||
| 119 | $now = dol_now(); |
||
| 120 | $filesarray = array(); |
||
| 121 | |||
| 122 | if ($choice == 'tempfiles' || $choice == 'tempfilesold') { |
||
| 123 | // Delete temporary files |
||
| 124 | if ($dolibarr_main_data_root) { |
||
| 125 | $filesarray = dol_dir_list($dolibarr_main_data_root, "directories", 1, '^temp$', '', 'name', SORT_ASC, 2, 0, '', 1); // Do not follow symlinks |
||
| 126 | |||
| 127 | if ($choice == 'tempfilesold') { |
||
| 128 | foreach ($filesarray as $key => $val) { |
||
| 129 | if ($val['date'] > ($now - ($nbsecondsold))) { |
||
| 130 | unset($filesarray[$key]); // Discard temp dir not older than $nbsecondsold |
||
| 131 | } |
||
| 132 | } |
||
| 133 | } |
||
| 134 | } |
||
| 135 | } |
||
| 136 | |||
| 137 | if ($choice == 'allfiles') { |
||
| 138 | // Delete all files (except .lock and .unlock files, do not follow symbolic links) |
||
| 139 | if ($dolibarr_main_data_root) { |
||
| 140 | $filesarray = dol_dir_list($dolibarr_main_data_root, "all", 0, '', '(\.lock|\.unlock)$', 'name', SORT_ASC, 0, 0, '', 1); // No need to use recursive, we will delete directory |
||
| 141 | } |
||
| 142 | } |
||
| 143 | |||
| 144 | if ($choice == 'allfilesold') { |
||
| 145 | // Delete all files (except .lock and .unlock files, do not follow symbolic links) |
||
| 146 | if ($dolibarr_main_data_root) { |
||
| 147 | $filesarray = dol_dir_list($dolibarr_main_data_root, "files", 1, '', '(\.lock|\.unlock)$', 'name', SORT_ASC, 0, 0, '', 1, $nbsecondsold); // No need to use recursive, we will delete directory |
||
| 148 | } |
||
| 149 | } |
||
| 150 | |||
| 151 | if ($choice == 'logfile' || $choice == 'logfiles') { |
||
| 152 | // Define files log |
||
| 153 | if ($dolibarr_main_data_root) { |
||
| 154 | $filesarray = dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*(\.gz)?$', '(\.lock|\.unlock)$', 'name', SORT_ASC, 0, 0, '', 1); |
||
| 155 | } |
||
| 156 | |||
| 157 | if (isModEnabled('syslog')) { |
||
| 158 | $filelog = getDolGlobalString('SYSLOG_FILE'); |
||
| 159 | $filelog = preg_replace('/DOL_DATA_ROOT/i', DOL_DATA_ROOT, $filelog); |
||
| 160 | |||
| 161 | $alreadyincluded = false; |
||
| 162 | foreach ($filesarray as $tmpcursor) { |
||
| 163 | if ($tmpcursor['fullname'] == $filelog) { |
||
| 164 | $alreadyincluded = true; |
||
| 165 | } |
||
| 166 | } |
||
| 167 | if (!$alreadyincluded) { |
||
| 168 | $filesarray[] = array('fullname' => $filelog, 'type' => 'file'); |
||
| 169 | } |
||
| 170 | } |
||
| 171 | } |
||
| 172 | |||
| 173 | if (is_array($filesarray) && count($filesarray)) { |
||
| 174 | foreach ($filesarray as $key => $value) { |
||
| 175 | //print "x ".$filesarray[$key]['fullname']."-".$filesarray[$key]['type']."<br>\n"; |
||
| 176 | if ($filesarray[$key]['type'] == 'dir') { |
||
| 177 | $startcount = 0; |
||
| 178 | $tmpcountdeleted = 0; |
||
| 179 | |||
| 180 | $result = dol_delete_dir_recursive($filesarray[$key]['fullname'], $startcount, 1, 0, $tmpcountdeleted); |
||
| 181 | $excluded = [ |
||
| 182 | $conf->user->dir_temp, |
||
| 183 | ]; |
||
| 184 | if (isModEnabled('api')) { |
||
| 185 | $excluded[] = $conf->api->dir_temp; |
||
| 186 | } |
||
| 187 | // The 2 directories $conf->api->dir_temp and $conf->user->dir_temp are recreated at end, so we do not count them |
||
| 188 | if (!in_array($filesarray[$key]['fullname'], $excluded)) { |
||
| 189 | $count += $result; |
||
| 190 | $countdeleted += $tmpcountdeleted; |
||
| 191 | } |
||
| 192 | } elseif ($filesarray[$key]['type'] == 'file') { |
||
| 193 | if ($choice != 'allfilesold' || $filesarray[$key]['date'] < ($now - $nbsecondsold)) { |
||
| 194 | // If (file that is not logfile) or (if mode is logfile) |
||
| 195 | if ($filesarray[$key]['fullname'] != $filelog || $choice == 'logfile' || $choice == 'logfiles') { |
||
| 196 | $result = dol_delete_file($filesarray[$key]['fullname'], 1, 1); |
||
| 197 | if ($result) { |
||
| 198 | $count++; |
||
| 199 | $countdeleted++; |
||
| 200 | } else { |
||
| 201 | $counterror++; |
||
| 202 | } |
||
| 203 | } |
||
| 204 | } |
||
| 205 | } |
||
| 206 | } |
||
| 207 | |||
| 208 | // Update cachenbofdoc |
||
| 209 | if (isModEnabled('ecm') && $choice == 'allfiles') { |
||
| 210 | require_once constant('DOL_DOCUMENT_ROOT') . '/ecm/class/ecmdirectory.class.php'; |
||
| 211 | $ecmdirstatic = new EcmDirectory($this->db); |
||
|
|
|||
| 212 | $result = $ecmdirstatic->refreshcachenboffile(1); |
||
| 213 | } |
||
| 214 | } |
||
| 215 | } |
||
| 216 | |||
| 217 | if ($count > 0) { |
||
| 218 | $langs->load("admin"); |
||
| 219 | $this->output = $langs->trans("PurgeNDirectoriesDeleted", $countdeleted); |
||
| 220 | if ($count > $countdeleted) { |
||
| 221 | $this->output .= '<br>' . $langs->trans("PurgeNDirectoriesFailed", ($count - $countdeleted)); |
||
| 222 | } |
||
| 223 | } else { |
||
| 224 | $this->output = $langs->trans("PurgeNothingToDelete") . (in_array('tempfilesold', $choicesarray) ? ' (older than 24h for temp files)' : ''); |
||
| 225 | } |
||
| 226 | |||
| 227 | // Recreate temp dir that are not automatically recreated by core code for performance purpose, we need them |
||
| 228 | if (isModEnabled('api')) { |
||
| 229 | dol_mkdir($conf->api->dir_temp); |
||
| 230 | } |
||
| 231 | dol_mkdir($conf->user->dir_temp); |
||
| 232 | |||
| 233 | //return $count; |
||
| 234 | return 0; // This function can be called by cron so must return 0 if OK |
||
| 235 | } |
||
| 236 | |||
| 237 | |||
| 238 | /** |
||
| 239 | * Make a backup of database |
||
| 240 | * CAN BE A CRON TASK |
||
| 241 | * |
||
| 242 | * @param string $compression 'gz' or 'bz' or 'none' |
||
| 243 | * @param string $type 'mysql', 'postgresql', ... |
||
| 244 | * @param int $usedefault 1=Use default backup profile (Set this to 1 when used as cron) |
||
| 245 | * @param string $file 'auto' or filename to build |
||
| 246 | * @param int $keeplastnfiles Keep only last n files (not used yet) |
||
| 247 | * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec' - need size of dump in memory, but low memory method is used if GETPOST('lowmemorydump') is set, 2=Use the 'popen' method (low memory method) |
||
| 248 | * @param int $lowmemorydump 1=Use the low memory method. If $lowmemorydump is set, it means we want to make the compression using an external pipe instead retrieving the content of the dump in PHP memory array $output_arr and then print it into the PHP pipe open with xopen(). |
||
| 249 | * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) |
||
| 250 | */ |
||
| 251 | public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0, $lowmemorydump = 0) |
||
| 252 | { |
||
| 253 | global $db, $conf, $langs, $dolibarr_main_data_root; |
||
| 254 | global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass; |
||
| 255 | global $dolibarr_main_db_character_set; |
||
| 256 | |||
| 257 | $langs->load("admin"); |
||
| 258 | |||
| 259 | dol_syslog("Utils::dumpDatabase type=" . $type . " compression=" . $compression . " file=" . $file, LOG_DEBUG); |
||
| 260 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; |
||
| 261 | |||
| 262 | // Clean data |
||
| 263 | $file = dol_sanitizeFileName($file); |
||
| 264 | |||
| 265 | // Check compression parameter |
||
| 266 | if (!in_array($compression, array('none', 'gz', 'bz', 'zip', 'zstd'))) { |
||
| 267 | $langs->load("errors"); |
||
| 268 | $this->error = $langs->transnoentitiesnoconv("ErrorBadValueForParameter", $compression, "Compression"); |
||
| 269 | return -1; |
||
| 270 | } |
||
| 271 | |||
| 272 | // Check type parameter |
||
| 273 | if ($type == 'auto') { |
||
| 274 | $type = $this->db->type; |
||
| 275 | } |
||
| 276 | if (!in_array($type, array('postgresql', 'pgsql', 'mysql', 'mysqli', 'mysqlnobin'))) { |
||
| 277 | $langs->load("errors"); |
||
| 278 | $this->error = $langs->transnoentitiesnoconv("ErrorBadValueForParameter", $type, "Basetype"); |
||
| 279 | return -1; |
||
| 280 | } |
||
| 281 | |||
| 282 | // Check file parameter |
||
| 283 | if ($file == 'auto') { |
||
| 284 | $prefix = 'dump'; |
||
| 285 | $ext = 'sql'; |
||
| 286 | if (in_array($type, array('mysql', 'mysqli'))) { |
||
| 287 | $prefix = 'mysqldump'; |
||
| 288 | } |
||
| 289 | //if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; } |
||
| 290 | if (in_array($type, array('pgsql'))) { |
||
| 291 | $prefix = 'pg_dump'; |
||
| 292 | } |
||
| 293 | $file = $prefix . '_' . $dolibarr_main_db_name . '_' . dol_sanitizeFileName(DOL_VERSION) . '_' . dol_print_date(dol_now('gmt'), "dayhourlogsmall", 'tzuser') . '.' . $ext; |
||
| 294 | } |
||
| 295 | |||
| 296 | $outputdir = $conf->admin->dir_output . '/backup'; |
||
| 297 | $result = dol_mkdir($outputdir); |
||
| 298 | $errormsg = ''; |
||
| 299 | |||
| 300 | // MYSQL |
||
| 301 | if ($type == 'mysql' || $type == 'mysqli') { |
||
| 302 | if (!getDolGlobalString('SYSTEMTOOLS_MYSQLDUMP')) { |
||
| 303 | $cmddump = $db->getPathOfDump(); |
||
| 304 | } else { |
||
| 305 | $cmddump = getDolGlobalString('SYSTEMTOOLS_MYSQLDUMP'); |
||
| 306 | } |
||
| 307 | if (empty($cmddump)) { |
||
| 308 | $this->error = "Failed to detect command to use for mysqldump. Try a manual backup before to set path of command."; |
||
| 309 | return -1; |
||
| 310 | } |
||
| 311 | |||
| 312 | $outputfile = $outputdir . '/' . $file; |
||
| 313 | // for compression format, we add extension |
||
| 314 | $compression = $compression ? $compression : 'none'; |
||
| 315 | if ($compression == 'gz') { |
||
| 316 | $outputfile .= '.gz'; |
||
| 317 | } elseif ($compression == 'bz') { |
||
| 318 | $outputfile .= '.bz2'; |
||
| 319 | } elseif ($compression == 'zstd') { |
||
| 320 | $outputfile .= '.zst'; |
||
| 321 | } |
||
| 322 | $outputerror = $outputfile . '.err'; |
||
| 323 | dol_mkdir($conf->admin->dir_output . '/backup'); |
||
| 324 | |||
| 325 | // Parameters execution |
||
| 326 | $command = $cmddump; |
||
| 327 | $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. |
||
| 328 | if (preg_match("/\s/", $command)) { |
||
| 329 | $command = escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters |
||
| 330 | } |
||
| 331 | |||
| 332 | //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); |
||
| 333 | $param = $dolibarr_main_db_name . " -h " . $dolibarr_main_db_host; |
||
| 334 | $param .= " -u " . $dolibarr_main_db_user; |
||
| 335 | if (!empty($dolibarr_main_db_port)) { |
||
| 336 | $param .= " -P " . $dolibarr_main_db_port . " --protocol=tcp"; |
||
| 337 | } |
||
| 338 | if (GETPOST("use_transaction", "alpha")) { |
||
| 339 | $param .= " --single-transaction"; |
||
| 340 | } |
||
| 341 | if (GETPOST("disable_fk", "alpha") || $usedefault) { |
||
| 342 | $param .= " -K"; |
||
| 343 | } |
||
| 344 | if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') { |
||
| 345 | $param .= " --compatible=" . escapeshellarg(GETPOST("sql_compat", "alpha")); |
||
| 346 | } |
||
| 347 | if (GETPOST("drop_database", "alpha")) { |
||
| 348 | $param .= " --add-drop-database"; |
||
| 349 | } |
||
| 350 | if (GETPOST("use_mysql_quick_param", "alpha")) { |
||
| 351 | $param .= " --quick"; |
||
| 352 | } |
||
| 353 | if (GETPOST("use_force", "alpha")) { |
||
| 354 | $param .= " -f"; |
||
| 355 | } |
||
| 356 | if (GETPOST("sql_structure", "alpha") || $usedefault) { |
||
| 357 | if (GETPOST("drop", "alpha") || $usedefault) { |
||
| 358 | $param .= " --add-drop-table=TRUE"; |
||
| 359 | } else { |
||
| 360 | $param .= " --add-drop-table=FALSE"; |
||
| 361 | } |
||
| 362 | } else { |
||
| 363 | $param .= " -t"; |
||
| 364 | } |
||
| 365 | if (GETPOST("disable-add-locks", "alpha")) { |
||
| 366 | $param .= " --add-locks=FALSE"; |
||
| 367 | } |
||
| 368 | if (GETPOST("sql_data", "alpha") || $usedefault) { |
||
| 369 | $param .= " --tables"; |
||
| 370 | if (GETPOST("showcolumns", "alpha") || $usedefault) { |
||
| 371 | $param .= " -c"; |
||
| 372 | } |
||
| 373 | if (GETPOST("extended_ins", "alpha") || $usedefault) { |
||
| 374 | $param .= " -e"; |
||
| 375 | } else { |
||
| 376 | $param .= " --skip-extended-insert"; |
||
| 377 | } |
||
| 378 | if (GETPOST("delayed", "alpha")) { |
||
| 379 | $param .= " --delayed-insert"; |
||
| 380 | } |
||
| 381 | if (GETPOST("sql_ignore", "alpha")) { |
||
| 382 | $param .= " --insert-ignore"; |
||
| 383 | } |
||
| 384 | if (GETPOST("hexforbinary", "alpha") || $usedefault) { |
||
| 385 | $param .= " --hex-blob"; |
||
| 386 | } |
||
| 387 | } else { |
||
| 388 | $param .= " -d"; // No row information (no data) |
||
| 389 | } |
||
| 390 | if ($dolibarr_main_db_character_set == 'utf8mb4') { |
||
| 391 | // We save output into utf8mb4 charset |
||
| 392 | $param .= " --default-character-set=utf8mb4 --no-tablespaces"; |
||
| 393 | } else { |
||
| 394 | $param .= " --default-character-set=utf8 --no-tablespaces"; // We always save output into utf8 charset |
||
| 395 | } |
||
| 396 | $paramcrypted = $param; |
||
| 397 | $paramclear = $param; |
||
| 398 | if (!empty($dolibarr_main_db_pass)) { |
||
| 399 | $paramcrypted .= ' -p"' . preg_replace('/./i', '*', $dolibarr_main_db_pass) . '"'; |
||
| 400 | $paramclear .= ' -p"' . str_replace(array('"', '`', '$'), array('\"', '\`', '\$'), $dolibarr_main_db_pass) . '"'; |
||
| 401 | } |
||
| 402 | |||
| 403 | $handle = ''; |
||
| 404 | |||
| 405 | // Start call method to execute dump |
||
| 406 | $fullcommandcrypted = $command . " " . $paramcrypted . " 2>&1"; |
||
| 407 | $fullcommandclear = $command . " " . $paramclear . " 2>&1"; |
||
| 408 | if (!$lowmemorydump) { |
||
| 409 | if ($compression == 'none') { |
||
| 410 | $handle = fopen($outputfile, 'w'); |
||
| 411 | } elseif ($compression == 'gz') { |
||
| 412 | $handle = gzopen($outputfile, 'w'); |
||
| 413 | } elseif ($compression == 'bz') { |
||
| 414 | $handle = bzopen($outputfile, 'w'); |
||
| 415 | } elseif ($compression == 'zstd') { |
||
| 416 | $handle = fopen($outputfile, 'w'); |
||
| 417 | } |
||
| 418 | } else { |
||
| 419 | if ($compression == 'none') { |
||
| 420 | $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 421 | $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 422 | $handle = 1; |
||
| 423 | } elseif ($compression == 'gz') { |
||
| 424 | $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 425 | $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 426 | $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | gzip'; |
||
| 427 | $handle = 1; |
||
| 428 | } elseif ($compression == 'bz') { |
||
| 429 | $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2 > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 430 | $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2 > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 431 | $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | bzip2'; |
||
| 432 | $handle = 1; |
||
| 433 | } elseif ($compression == 'zstd') { |
||
| 434 | $fullcommandclear .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 435 | $fullcommandcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd > "' . dol_sanitizePathName($outputfile) . '"'; |
||
| 436 | $paramcrypted .= ' | grep -v "Warning: Using a password on the command line interface can be insecure." | zstd'; |
||
| 437 | $handle = 1; |
||
| 438 | } |
||
| 439 | } |
||
| 440 | |||
| 441 | $ok = 0; |
||
| 442 | if ($handle) { |
||
| 443 | if (getDolGlobalString('MAIN_EXEC_USE_POPEN')) { |
||
| 444 | $execmethod = getDolGlobalString('MAIN_EXEC_USE_POPEN'); |
||
| 445 | } |
||
| 446 | if (empty($execmethod)) { |
||
| 447 | $execmethod = 1; |
||
| 448 | } |
||
| 449 | |||
| 450 | dol_syslog("Utils::dumpDatabase execmethod=" . $execmethod . " command:" . $fullcommandcrypted, LOG_INFO); |
||
| 451 | |||
| 452 | |||
| 453 | /* If value has been forced with a php_admin_value, this has no effect. Example of value: '512M' */ |
||
| 454 | $MemoryLimit = getDolGlobalString('MAIN_MEMORY_LIMIT_DUMP'); |
||
| 455 | if (!empty($MemoryLimit)) { |
||
| 456 | @ini_set('memory_limit', $MemoryLimit); |
||
| 457 | } |
||
| 458 | |||
| 459 | |||
| 460 | if ($execmethod == 1) { |
||
| 461 | $output_arr = array(); |
||
| 462 | $retval = null; |
||
| 463 | |||
| 464 | exec($fullcommandclear, $output_arr, $retval); |
||
| 465 | // TODO Replace this exec with Utils->executeCLI() function. |
||
| 466 | // We must check that the case for $lowmemorydump works too... |
||
| 467 | //$utils = new Utils($db); |
||
| 468 | //$outputfile = $conf->admin->dir_temp.'/dump.tmp'; |
||
| 469 | //$utils->executeCLI($fullcommandclear, $outputfile, 0); |
||
| 470 | |||
| 471 | if ($retval != 0) { |
||
| 472 | $langs->load("errors"); |
||
| 473 | dol_syslog("Datadump retval after exec=" . $retval, LOG_ERR); |
||
| 474 | $errormsg = 'Error ' . $retval; |
||
| 475 | $ok = 0; |
||
| 476 | } else { |
||
| 477 | $i = 0; |
||
| 478 | if (!empty($output_arr)) { |
||
| 479 | foreach ($output_arr as $key => $read) { |
||
| 480 | $i++; // output line number |
||
| 481 | if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) { |
||
| 482 | continue; |
||
| 483 | } |
||
| 484 | // Now check into the result file, that the file end with "-- Dump completed" |
||
| 485 | // This is possible only if $output_arr is the clear dump file, so not possible with $lowmemorydump set because file is already compressed. |
||
| 486 | if (!$lowmemorydump) { |
||
| 487 | fwrite($handle, $read . ($execmethod == 2 ? '' : "\n")); |
||
| 488 | if (preg_match('/' . preg_quote('-- Dump completed', '/') . '/i', $read)) { |
||
| 489 | $ok = 1; |
||
| 490 | } elseif (preg_match('/' . preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES', '/') . '/i', $read)) { |
||
| 491 | $ok = 1; |
||
| 492 | } |
||
| 493 | } else { |
||
| 494 | // If we have a result here in lowmemorydump mode, something is strange |
||
| 495 | } |
||
| 496 | } |
||
| 497 | } elseif ($lowmemorydump) { |
||
| 498 | $ok = 1; |
||
| 499 | } |
||
| 500 | } |
||
| 501 | } |
||
| 502 | |||
| 503 | if ($execmethod == 2) { // With this method, there is no way to get the return code, only output |
||
| 504 | $handlein = popen($fullcommandclear, 'r'); |
||
| 505 | $i = 0; |
||
| 506 | if ($handlein) { |
||
| 507 | while (!feof($handlein)) { |
||
| 508 | $i++; // output line number |
||
| 509 | $read = fgets($handlein); |
||
| 510 | // Exclude warning line we don't want |
||
| 511 | if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) { |
||
| 512 | continue; |
||
| 513 | } |
||
| 514 | fwrite($handle, $read); |
||
| 515 | if (preg_match('/' . preg_quote('-- Dump completed') . '/i', $read)) { |
||
| 516 | $ok = 1; |
||
| 517 | } elseif (preg_match('/' . preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES') . '/i', $read)) { |
||
| 518 | $ok = 1; |
||
| 519 | } |
||
| 520 | } |
||
| 521 | pclose($handlein); |
||
| 522 | } |
||
| 523 | } |
||
| 524 | |||
| 525 | if (!$lowmemorydump) { |
||
| 526 | if ($compression == 'none') { |
||
| 527 | fclose($handle); |
||
| 528 | } elseif ($compression == 'gz') { |
||
| 529 | gzclose($handle); |
||
| 530 | } elseif ($compression == 'bz') { |
||
| 531 | fclose($handle); |
||
| 532 | } elseif ($compression == 'zstd') { |
||
| 533 | fclose($handle); |
||
| 534 | } |
||
| 535 | } |
||
| 536 | |||
| 537 | dolChmod($outputfile); |
||
| 538 | } else { |
||
| 539 | $langs->load("errors"); |
||
| 540 | dol_syslog("Failed to open file " . $outputfile, LOG_ERR); |
||
| 541 | $errormsg = $langs->trans("ErrorFailedToWriteInDir"); |
||
| 542 | } |
||
| 543 | |||
| 544 | // Get errorstring |
||
| 545 | if ($compression == 'none') { |
||
| 546 | $handle = fopen($outputfile, 'r'); |
||
| 547 | } elseif ($compression == 'gz') { |
||
| 548 | $handle = gzopen($outputfile, 'r'); |
||
| 549 | } elseif ($compression == 'bz') { |
||
| 550 | $handle = bzopen($outputfile, 'r'); |
||
| 551 | } elseif ($compression == 'zstd') { |
||
| 552 | $handle = fopen($outputfile, 'r'); |
||
| 553 | } |
||
| 554 | if ($handle) { |
||
| 555 | // Get 2048 first chars of error message. |
||
| 556 | $errormsg = fgets($handle, 2048); |
||
| 557 | //$ok=0;$errormsg=''; To force error |
||
| 558 | |||
| 559 | // Close file |
||
| 560 | if ($compression == 'none') { |
||
| 561 | fclose($handle); |
||
| 562 | } elseif ($compression == 'gz') { |
||
| 563 | gzclose($handle); |
||
| 564 | } elseif ($compression == 'bz') { |
||
| 565 | fclose($handle); |
||
| 566 | } elseif ($compression == 'zstd') { |
||
| 567 | fclose($handle); |
||
| 568 | } |
||
| 569 | if ($ok && preg_match('/^-- (MySql|MariaDB)/i', $errormsg)) { // No error |
||
| 570 | $errormsg = ''; |
||
| 571 | } else { |
||
| 572 | // Renommer fichier sortie en fichier erreur |
||
| 573 | //print "$outputfile -> $outputerror"; |
||
| 574 | @dol_delete_file($outputerror, 1, 0, 0, null, false, 0); |
||
| 575 | @rename($outputfile, $outputerror); |
||
| 576 | // Si safe_mode on et command hors du parameter exec, on a un fichier out vide donc errormsg vide |
||
| 577 | if (!$errormsg) { |
||
| 578 | $langs->load("errors"); |
||
| 579 | $errormsg = $langs->trans("ErrorFailedToRunExternalCommand"); |
||
| 580 | } |
||
| 581 | } |
||
| 582 | } |
||
| 583 | // Fin execution commande |
||
| 584 | |||
| 585 | $this->output = $errormsg; |
||
| 586 | $this->error = $errormsg; |
||
| 587 | $this->result = array("commandbackuplastdone" => $command . " " . $paramcrypted, "commandbackuptorun" => ""); |
||
| 588 | //if (empty($this->output)) $this->output=$this->result['commandbackuplastdone']; |
||
| 589 | } |
||
| 590 | |||
| 591 | // MYSQL NO BIN |
||
| 592 | if ($type == 'mysqlnobin') { |
||
| 593 | $outputfile = $outputdir . '/' . $file; |
||
| 594 | $outputfiletemp = $outputfile . '-TMP.sql'; |
||
| 595 | // for compression format, we add extension |
||
| 596 | $compression = $compression ? $compression : 'none'; |
||
| 597 | if ($compression == 'gz') { |
||
| 598 | $outputfile .= '.gz'; |
||
| 599 | } |
||
| 600 | if ($compression == 'bz') { |
||
| 601 | $outputfile .= '.bz2'; |
||
| 602 | } |
||
| 603 | $outputerror = $outputfile . '.err'; |
||
| 604 | dol_mkdir($conf->admin->dir_output . '/backup'); |
||
| 605 | |||
| 606 | if ($compression == 'gz' or $compression == 'bz') { |
||
| 607 | $this->backupTables($outputfiletemp); |
||
| 608 | dol_compress_file($outputfiletemp, $outputfile, $compression); |
||
| 609 | unlink($outputfiletemp); |
||
| 610 | } else { |
||
| 611 | $this->backupTables($outputfile); |
||
| 612 | } |
||
| 613 | |||
| 614 | $this->output = ""; |
||
| 615 | $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => ""); |
||
| 616 | } |
||
| 617 | |||
| 618 | // POSTGRESQL |
||
| 619 | if ($type == 'postgresql' || $type == 'pgsql') { |
||
| 620 | $cmddump = getDolGlobalString('SYSTEMTOOLS_POSTGRESQLDUMP'); |
||
| 621 | |||
| 622 | $outputfile = $outputdir . '/' . $file; |
||
| 623 | // for compression format, we add extension |
||
| 624 | $compression = $compression ? $compression : 'none'; |
||
| 625 | if ($compression == 'gz') { |
||
| 626 | $outputfile .= '.gz'; |
||
| 627 | } |
||
| 628 | if ($compression == 'bz') { |
||
| 629 | $outputfile .= '.bz2'; |
||
| 630 | } |
||
| 631 | $outputerror = $outputfile . '.err'; |
||
| 632 | dol_mkdir($conf->admin->dir_output . '/backup'); |
||
| 633 | |||
| 634 | // Parameters execution |
||
| 635 | $command = $cmddump; |
||
| 636 | $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. |
||
| 637 | if (preg_match("/\s/", $command)) { |
||
| 638 | $command = escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters |
||
| 639 | } |
||
| 640 | |||
| 641 | //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); |
||
| 642 | //$param="-F c"; |
||
| 643 | $param = "-F p"; |
||
| 644 | $param .= " --no-tablespaces --inserts -h " . $dolibarr_main_db_host; |
||
| 645 | $param .= " -U " . $dolibarr_main_db_user; |
||
| 646 | if (!empty($dolibarr_main_db_port)) { |
||
| 647 | $param .= " -p " . $dolibarr_main_db_port; |
||
| 648 | } |
||
| 649 | if (GETPOST("sql_compat") && GETPOST("sql_compat") == 'ANSI') { |
||
| 650 | $param .= " --disable-dollar-quoting"; |
||
| 651 | } |
||
| 652 | if (GETPOST("drop_database")) { |
||
| 653 | $param .= " -c -C"; |
||
| 654 | } |
||
| 655 | if (GETPOST("sql_structure")) { |
||
| 656 | if (GETPOST("drop")) { |
||
| 657 | $param .= " --add-drop-table"; |
||
| 658 | } |
||
| 659 | if (!GETPOST("sql_data")) { |
||
| 660 | $param .= " -s"; |
||
| 661 | } |
||
| 662 | } |
||
| 663 | if (GETPOST("sql_data")) { |
||
| 664 | if (!GETPOST("sql_structure")) { |
||
| 665 | $param .= " -a"; |
||
| 666 | } |
||
| 667 | if (GETPOST("showcolumns")) { |
||
| 668 | $param .= " -c"; |
||
| 669 | } |
||
| 670 | } |
||
| 671 | $param .= ' -f "' . $outputfile . '"'; |
||
| 672 | //if ($compression == 'none') |
||
| 673 | if ($compression == 'gz') { |
||
| 674 | $param .= ' -Z 9'; |
||
| 675 | } |
||
| 676 | //if ($compression == 'bz') |
||
| 677 | $paramcrypted = $param; |
||
| 678 | $paramclear = $param; |
||
| 679 | /*if (!empty($dolibarr_main_db_pass)) |
||
| 680 | { |
||
| 681 | $paramcrypted.=" -W".preg_replace('/./i','*',$dolibarr_main_db_pass); |
||
| 682 | $paramclear.=" -W".$dolibarr_main_db_pass; |
||
| 683 | }*/ |
||
| 684 | $paramcrypted .= " -w " . $dolibarr_main_db_name; |
||
| 685 | $paramclear .= " -w " . $dolibarr_main_db_name; |
||
| 686 | |||
| 687 | $this->output = ""; |
||
| 688 | $this->result = array("commandbackuplastdone" => "", "commandbackuptorun" => $command . " " . $paramcrypted); |
||
| 689 | } |
||
| 690 | |||
| 691 | // Clean old files |
||
| 692 | if (!$errormsg && $keeplastnfiles > 0) { |
||
| 693 | $tmpfiles = dol_dir_list($conf->admin->dir_output . '/backup', 'files', 0, '', '(\.err|\.old|\.sav)$', 'date', SORT_DESC); |
||
| 694 | $i = 0; |
||
| 695 | if (is_array($tmpfiles)) { |
||
| 696 | foreach ($tmpfiles as $key => $val) { |
||
| 697 | $i++; |
||
| 698 | if ($i <= $keeplastnfiles) { |
||
| 699 | continue; |
||
| 700 | } |
||
| 701 | dol_delete_file($val['fullname'], 0, 0, 0, null, false, 0); |
||
| 702 | } |
||
| 703 | } |
||
| 704 | } |
||
| 705 | |||
| 706 | return ($errormsg ? -1 : 0); |
||
| 707 | } |
||
| 708 | |||
| 709 | /** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission) |
||
| 710 | * Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php) |
||
| 711 | * Updated and enhanced by Stephen Larroque (lrq3000) and by the many commentators from the blog |
||
| 712 | * Note about foreign keys constraints: for Dolibarr, since there are a lot of constraints and when imported the tables will be inserted in the dumped order, not in constraints order, then we ABSOLUTELY need to use SET FOREIGN_KEY_CHECKS=0; when importing the sql dump. |
||
| 713 | * Note2: db2SQL by Howard Yeend can be an alternative, by using SHOW FIELDS FROM and SHOW KEYS FROM we could generate a more precise dump (eg: by getting the type of the field and then precisely outputting the right formatting - in quotes, numeric or null - instead of trying to guess like we are doing now). |
||
| 714 | * |
||
| 715 | * @param string $outputfile Output file name |
||
| 716 | * @param string $tables Table name or '*' for all |
||
| 717 | * @return int Return integer <0 if KO, >0 if OK |
||
| 718 | */ |
||
| 719 | public function backupTables($outputfile, $tables = '*') |
||
| 720 | { |
||
| 721 | global $db, $langs; |
||
| 722 | global $errormsg; |
||
| 723 | |||
| 724 | // Set to UTF-8 |
||
| 725 | if (is_a($db, 'DoliDBMysqli')) { |
||
| 726 | /** @var DoliDBMysqli $db */ |
||
| 727 | $db->db->set_charset('utf8'); |
||
| 728 | } else { |
||
| 729 | /** @var DoliDB $db */ |
||
| 730 | $db->query('SET NAMES utf8'); |
||
| 731 | $db->query('SET CHARACTER SET utf8'); |
||
| 732 | } |
||
| 733 | |||
| 734 | //get all of the tables |
||
| 735 | if ($tables == '*') { |
||
| 736 | $tables = array(); |
||
| 737 | $result = $db->query('SHOW FULL TABLES WHERE Table_type = \'BASE TABLE\''); |
||
| 738 | while ($row = $db->fetch_row($result)) { |
||
| 739 | $tables[] = $row[0]; |
||
| 740 | } |
||
| 741 | } else { |
||
| 742 | $tables = is_array($tables) ? $tables : explode(',', $tables); |
||
| 743 | } |
||
| 744 | |||
| 745 | //cycle through |
||
| 746 | $handle = fopen($outputfile, 'w+'); |
||
| 747 | if (fwrite($handle, '') === false) { |
||
| 748 | $langs->load("errors"); |
||
| 749 | dol_syslog("Failed to open file " . $outputfile, LOG_ERR); |
||
| 750 | $errormsg = $langs->trans("ErrorFailedToWriteInDir"); |
||
| 751 | return -1; |
||
| 752 | } |
||
| 753 | |||
| 754 | // Print headers and global mysql config vars |
||
| 755 | $sqlhead = ''; |
||
| 756 | $sqlhead .= "-- " . $db::LABEL . " dump via php with Dolibarr " . DOL_VERSION . " |
||
| 757 | -- |
||
| 758 | -- Host: " . $db->db->host_info . " Database: " . $db->database_name . " |
||
| 759 | -- ------------------------------------------------------ |
||
| 760 | -- Server version " . $db->db->server_info . " |
||
| 761 | |||
| 762 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; |
||
| 763 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; |
||
| 764 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; |
||
| 765 | /*!40101 SET NAMES utf8 */; |
||
| 766 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; |
||
| 767 | /*!40103 SET TIME_ZONE='+00:00' */; |
||
| 768 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; |
||
| 769 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; |
||
| 770 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; |
||
| 771 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; |
||
| 772 | |||
| 773 | "; |
||
| 774 | |||
| 775 | if (GETPOST("nobin_disable_fk")) { |
||
| 776 | $sqlhead .= "SET FOREIGN_KEY_CHECKS=0;\n"; |
||
| 777 | } |
||
| 778 | //$sqlhead .= "SET SQL_MODE=\"NO_AUTO_VALUE_ON_ZERO\";\n"; |
||
| 779 | if (GETPOST("nobin_use_transaction")) { |
||
| 780 | $sqlhead .= "SET AUTOCOMMIT=0;\nSTART TRANSACTION;\n"; |
||
| 781 | } |
||
| 782 | |||
| 783 | fwrite($handle, $sqlhead); |
||
| 784 | |||
| 785 | $ignore = ''; |
||
| 786 | if (GETPOST("nobin_sql_ignore")) { |
||
| 787 | $ignore = 'IGNORE '; |
||
| 788 | } |
||
| 789 | $delayed = ''; |
||
| 790 | if (GETPOST("nobin_delayed")) { |
||
| 791 | $delayed = 'DELAYED '; |
||
| 792 | } |
||
| 793 | |||
| 794 | // Process each table and print their definition + their datas |
||
| 795 | foreach ($tables as $table) { |
||
| 796 | // Saving the table structure |
||
| 797 | fwrite($handle, "\n--\n-- Table structure for table `" . $table . "`\n--\n"); |
||
| 798 | |||
| 799 | if (GETPOST("nobin_drop")) { |
||
| 800 | fwrite($handle, "DROP TABLE IF EXISTS `" . $table . "`;\n"); // Dropping table if exists prior to re create it |
||
| 801 | } |
||
| 802 | fwrite($handle, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); |
||
| 803 | fwrite($handle, "/*!40101 SET character_set_client = utf8 */;\n"); |
||
| 804 | $resqldrop = $db->query('SHOW CREATE TABLE ' . $table); |
||
| 805 | $row2 = $db->fetch_row($resqldrop); |
||
| 806 | if (empty($row2[1])) { |
||
| 807 | fwrite($handle, "\n-- WARNING: Show create table " . $table . " return empty string when it should not.\n"); |
||
| 808 | } else { |
||
| 809 | fwrite($handle, $row2[1] . ";\n"); |
||
| 810 | //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n"); |
||
| 811 | |||
| 812 | // Dumping the data (locking the table and disabling the keys check while doing the process) |
||
| 813 | fwrite($handle, "\n--\n-- Dumping data for table `" . $table . "`\n--\n"); |
||
| 814 | if (!GETPOST("nobin_nolocks")) { |
||
| 815 | fwrite($handle, "LOCK TABLES `" . $table . "` WRITE;\n"); // Lock the table before inserting data (when the data will be imported back) |
||
| 816 | } |
||
| 817 | if (GETPOST("nobin_disable_fk")) { |
||
| 818 | fwrite($handle, "ALTER TABLE `" . $table . "` DISABLE KEYS;\n"); |
||
| 819 | } else { |
||
| 820 | fwrite($handle, "/*!40000 ALTER TABLE `" . $table . "` DISABLE KEYS */;\n"); |
||
| 821 | } |
||
| 822 | |||
| 823 | $sql = "SELECT * FROM " . $table; // Here SELECT * is allowed because we don't have definition of columns to take |
||
| 824 | $result = $db->query($sql); |
||
| 825 | while ($row = $db->fetch_row($result)) { |
||
| 826 | // For each row of data we print a line of INSERT |
||
| 827 | fwrite($handle, "INSERT " . $delayed . $ignore . "INTO " . $table . " VALUES ("); |
||
| 828 | $columns = count($row); |
||
| 829 | for ($j = 0; $j < $columns; $j++) { |
||
| 830 | // Processing each columns of the row to ensure that we correctly save the value (eg: add quotes for string - in fact we add quotes for everything, it's easier) |
||
| 831 | if ($row[$j] == null && !is_string($row[$j])) { |
||
| 832 | // IMPORTANT: if the field is NULL we set it NULL |
||
| 833 | $row[$j] = 'NULL'; |
||
| 834 | } elseif (is_string($row[$j]) && $row[$j] == '') { |
||
| 835 | // if it's an empty string, we set it as an empty string |
||
| 836 | $row[$j] = "''"; |
||
| 837 | } elseif (is_numeric($row[$j]) && !strcmp((string)$row[$j], (string)((float)$row[$j] + 0))) { // test if it's a numeric type and the numeric version ($nb+0) == string version (eg: if we have 01, it's probably not a number but rather a string, else it would not have any leading 0) |
||
| 838 | // if it's a number, we return it as-is |
||
| 839 | // $row[$j] = $row[$j]; |
||
| 840 | } else { // else for all other cases we escape the value and put quotes around |
||
| 841 | $row[$j] = addslashes($row[$j]); |
||
| 842 | $row[$j] = preg_replace("#\n#", "\\n", $row[$j]); |
||
| 843 | $row[$j] = "'" . $row[$j] . "'"; |
||
| 844 | } |
||
| 845 | } |
||
| 846 | fwrite($handle, implode(',', $row) . ");\n"); |
||
| 847 | } |
||
| 848 | if (GETPOST("nobin_disable_fk")) { |
||
| 849 | fwrite($handle, "ALTER TABLE `" . $table . "` ENABLE KEYS;\n"); // Enabling back the keys/index checking |
||
| 850 | } |
||
| 851 | if (!GETPOST("nobin_nolocks")) { |
||
| 852 | fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table |
||
| 853 | } |
||
| 854 | fwrite($handle, "\n\n\n"); |
||
| 855 | } |
||
| 856 | } |
||
| 857 | |||
| 858 | /* Backup Procedure structure*/ |
||
| 859 | /* |
||
| 860 | $result = $db->query('SHOW PROCEDURE STATUS'); |
||
| 861 | if ($db->num_rows($result) > 0) |
||
| 862 | { |
||
| 863 | while ($row = $db->fetch_row($result)) { $procedures[] = $row[1]; } |
||
| 864 | foreach($procedures as $proc) |
||
| 865 | { |
||
| 866 | fwrite($handle,"DELIMITER $$\n\n"); |
||
| 867 | fwrite($handle,"DROP PROCEDURE IF EXISTS '$name'.'$proc'$$\n"); |
||
| 868 | $resqlcreateproc=$db->query("SHOW CREATE PROCEDURE '$proc'"); |
||
| 869 | $row2 = $db->fetch_row($resqlcreateproc); |
||
| 870 | fwrite($handle,"\n".$row2[2]."$$\n\n"); |
||
| 871 | fwrite($handle,"DELIMITER ;\n\n"); |
||
| 872 | } |
||
| 873 | } |
||
| 874 | */ |
||
| 875 | /* Backup Procedure structure*/ |
||
| 876 | |||
| 877 | // Write the footer (restore the previous database settings) |
||
| 878 | $sqlfooter = "\n\n"; |
||
| 879 | if (GETPOST("nobin_use_transaction")) { |
||
| 880 | $sqlfooter .= "COMMIT;\n"; |
||
| 881 | } |
||
| 882 | if (GETPOST("nobin_disable_fk")) { |
||
| 883 | $sqlfooter .= "SET FOREIGN_KEY_CHECKS=1;\n"; |
||
| 884 | } |
||
| 885 | $sqlfooter .= "\n\n-- Dump completed on " . date('Y-m-d G-i-s'); |
||
| 886 | fwrite($handle, $sqlfooter); |
||
| 887 | |||
| 888 | fclose($handle); |
||
| 889 | |||
| 890 | return 1; |
||
| 891 | } |
||
| 892 | |||
| 893 | /** |
||
| 894 | * Generate documentation of a Module |
||
| 895 | * |
||
| 896 | * @param string $module Module name |
||
| 897 | * @return int Return integer <0 if KO, >0 if OK |
||
| 898 | */ |
||
| 899 | public function generateDoc($module) |
||
| 900 | { |
||
| 901 | global $conf, $langs, $user, $mysoc; |
||
| 902 | global $dirins; |
||
| 903 | |||
| 904 | $error = 0; |
||
| 905 | |||
| 906 | $modulelowercase = strtolower($module); |
||
| 907 | $now = dol_now(); |
||
| 908 | |||
| 909 | // Dir for module |
||
| 910 | $dir = $dirins . '/' . $modulelowercase; |
||
| 911 | // Zip file to build |
||
| 912 | $FILENAMEDOC = ''; |
||
| 913 | |||
| 914 | // Load module |
||
| 915 | dol_include_once($modulelowercase . '/core/modules/mod' . $module . '.class.php'); |
||
| 916 | $class = 'mod' . $module; |
||
| 917 | |||
| 918 | if (class_exists($class)) { |
||
| 919 | try { |
||
| 920 | $moduleobj = new $class($this->db); |
||
| 921 | } catch (Exception $e) { |
||
| 922 | $error++; |
||
| 923 | dol_print_error(null, $e->getMessage()); |
||
| 924 | } |
||
| 925 | } else { |
||
| 926 | $error++; |
||
| 927 | $langs->load("errors"); |
||
| 928 | dol_print_error(null, $langs->trans("ErrorFailedToLoadModuleDescriptorForXXX", $module)); |
||
| 929 | exit; |
||
| 930 | } |
||
| 931 | |||
| 932 | $arrayversion = explode('.', $moduleobj->version, 3); |
||
| 933 | if (count($arrayversion)) { |
||
| 934 | $FILENAMEASCII = strtolower($module) . '.asciidoc'; |
||
| 935 | $FILENAMEDOC = strtolower($module) . '.html'; |
||
| 936 | $FILENAMEDOCPDF = strtolower($module) . '.pdf'; |
||
| 937 | |||
| 938 | $dirofmodule = dol_buildpath(strtolower($module), 0); |
||
| 939 | $dirofmoduledoc = dol_buildpath(strtolower($module), 0) . '/doc'; |
||
| 940 | $dirofmoduletmp = dol_buildpath(strtolower($module), 0) . '/doc/temp'; |
||
| 941 | $outputfiledoc = $dirofmoduledoc . '/' . $FILENAMEDOC; |
||
| 942 | if ($dirofmoduledoc) { |
||
| 943 | if (!dol_is_dir($dirofmoduledoc)) { |
||
| 944 | dol_mkdir($dirofmoduledoc); |
||
| 945 | } |
||
| 946 | if (!dol_is_dir($dirofmoduletmp)) { |
||
| 947 | dol_mkdir($dirofmoduletmp); |
||
| 948 | } |
||
| 949 | if (!is_writable($dirofmoduletmp)) { |
||
| 950 | $this->error = 'Dir ' . $dirofmoduletmp . ' does not exists or is not writable'; |
||
| 951 | return -1; |
||
| 952 | } |
||
| 953 | |||
| 954 | if (!getDolGlobalString('MODULEBUILDER_ASCIIDOCTOR') && !getDolGlobalString('MODULEBUILDER_ASCIIDOCTORPDF')) { |
||
| 955 | $this->error = 'Setup of module ModuleBuilder not complete'; |
||
| 956 | return -1; |
||
| 957 | } |
||
| 958 | |||
| 959 | // Copy some files into temp directory, so instruction include::ChangeLog.md[] will works inside the asciidoc file. |
||
| 960 | dol_copy($dirofmodule . '/README.md', $dirofmoduletmp . '/README.md', 0, 1); |
||
| 961 | dol_copy($dirofmodule . '/ChangeLog.md', $dirofmoduletmp . '/ChangeLog.md', 0, 1); |
||
| 962 | |||
| 963 | // Replace into README.md and ChangeLog.md (in case they are included into documentation with tag __README__ or __CHANGELOG__) |
||
| 964 | $arrayreplacement = array(); |
||
| 965 | $arrayreplacement['/^#\s.*/m'] = ''; // Remove first level of title into .md files |
||
| 966 | $arrayreplacement['/^#/m'] = '##'; // Add on # to increase level |
||
| 967 | |||
| 968 | dolReplaceInFile($dirofmoduletmp . '/README.md', $arrayreplacement, '', 0, 0, 1); |
||
| 969 | dolReplaceInFile($dirofmoduletmp . '/ChangeLog.md', $arrayreplacement, '', 0, 0, 1); |
||
| 970 | |||
| 971 | |||
| 972 | $destfile = $dirofmoduletmp . '/' . $FILENAMEASCII; |
||
| 973 | |||
| 974 | $fhandle = fopen($destfile, 'w+'); |
||
| 975 | if ($fhandle) { |
||
| 976 | $specs = dol_dir_list(dol_buildpath(strtolower($module) . '/doc', 0), 'files', 1, '(\.md|\.asciidoc)$', array('\/temp\/')); |
||
| 977 | |||
| 978 | $i = 0; |
||
| 979 | foreach ($specs as $spec) { |
||
| 980 | if (preg_match('/notindoc/', $spec['relativename'])) { |
||
| 981 | continue; // Discard file |
||
| 982 | } |
||
| 983 | if (preg_match('/example/', $spec['relativename'])) { |
||
| 984 | continue; // Discard file |
||
| 985 | } |
||
| 986 | if (preg_match('/disabled/', $spec['relativename'])) { |
||
| 987 | continue; // Discard file |
||
| 988 | } |
||
| 989 | |||
| 990 | $pathtofile = strtolower($module) . '/doc/' . $spec['relativename']; |
||
| 991 | $format = 'asciidoc'; |
||
| 992 | if (preg_match('/\.md$/i', $spec['name'])) { |
||
| 993 | $format = 'markdown'; |
||
| 994 | } |
||
| 995 | |||
| 996 | $filecursor = @file_get_contents($spec['fullname']); |
||
| 997 | if ($filecursor) { |
||
| 998 | fwrite($fhandle, ($i ? "\n<<<\n\n" : "") . $filecursor . "\n"); |
||
| 999 | } else { |
||
| 1000 | $this->error = 'Failed to concat content of file ' . $spec['fullname']; |
||
| 1001 | return -1; |
||
| 1002 | } |
||
| 1003 | |||
| 1004 | $i++; |
||
| 1005 | } |
||
| 1006 | |||
| 1007 | fclose($fhandle); |
||
| 1008 | |||
| 1009 | $contentreadme = file_get_contents($dirofmoduletmp . '/README.md'); |
||
| 1010 | $contentchangelog = file_get_contents($dirofmoduletmp . '/ChangeLog.md'); |
||
| 1011 | |||
| 1012 | include DOL_DOCUMENT_ROOT . '/core/lib/parsemd.lib.php'; |
||
| 1013 | |||
| 1014 | //var_dump($phpfileval['fullname']); |
||
| 1015 | $arrayreplacement = array( |
||
| 1016 | 'mymodule' => strtolower($module), |
||
| 1017 | 'MyModule' => $module, |
||
| 1018 | 'MYMODULE' => strtoupper($module), |
||
| 1019 | 'My module' => $module, |
||
| 1020 | 'my module' => $module, |
||
| 1021 | 'Mon module' => $module, |
||
| 1022 | 'mon module' => $module, |
||
| 1023 | 'htdocs/modulebuilder/template' => strtolower($module), |
||
| 1024 | '__MYCOMPANY_NAME__' => $mysoc->name, |
||
| 1025 | '__KEYWORDS__' => $module, |
||
| 1026 | '__USER_FULLNAME__' => $user->getFullName($langs), |
||
| 1027 | '__USER_EMAIL__' => $user->email, |
||
| 1028 | '__YYYY-MM-DD__' => dol_print_date($now, 'dayrfc'), |
||
| 1029 | '---Put here your own copyright and developer email---' => dol_print_date($now, 'dayrfc') . ' ' . $user->getFullName($langs) . ($user->email ? ' <' . $user->email . '>' : ''), |
||
| 1030 | '__DATA_SPECIFICATION__' => 'Not yet available', |
||
| 1031 | '__README__' => dolMd2Asciidoc($contentreadme), |
||
| 1032 | '__CHANGELOG__' => dolMd2Asciidoc($contentchangelog), |
||
| 1033 | ); |
||
| 1034 | |||
| 1035 | // @phan-suppress-next-line PhanPluginSuspiciousParamPosition |
||
| 1036 | dolReplaceInFile($destfile, $arrayreplacement); |
||
| 1037 | } |
||
| 1038 | |||
| 1039 | // Launch doc generation |
||
| 1040 | $currentdir = getcwd(); |
||
| 1041 | chdir($dirofmodule); |
||
| 1042 | |||
| 1043 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/class/utils.class.php'; |
||
| 1044 | $utils = new Utils($this->db); |
||
| 1045 | |||
| 1046 | // Build HTML doc |
||
| 1047 | $command = getDolGlobalString('MODULEBUILDER_ASCIIDOCTOR') . ' ' . $destfile . ' -n -o ' . $dirofmoduledoc . '/' . $FILENAMEDOC; |
||
| 1048 | $outfile = $dirofmoduletmp . '/out.tmp'; |
||
| 1049 | |||
| 1050 | $resarray = $utils->executeCLI($command, $outfile); |
||
| 1051 | if ($resarray['result'] != '0') { |
||
| 1052 | $this->error = $resarray['error'] . ' ' . $resarray['output']; |
||
| 1053 | $this->errors[] = $this->error; |
||
| 1054 | } |
||
| 1055 | $result = ($resarray['result'] == 0) ? 1 : 0; |
||
| 1056 | if ($result < 0 && empty($this->errors)) { |
||
| 1057 | $this->error = $langs->trans("ErrorFailToGenerateFile", $FILENAMEDOC); |
||
| 1058 | $this->errors[] = $this->error; |
||
| 1059 | } |
||
| 1060 | |||
| 1061 | // Build PDF doc |
||
| 1062 | $command = getDolGlobalString('MODULEBUILDER_ASCIIDOCTORPDF') . ' ' . $destfile . ' -n -o ' . $dirofmoduledoc . '/' . $FILENAMEDOCPDF; |
||
| 1063 | $outfile = $dirofmoduletmp . '/outpdf.tmp'; |
||
| 1064 | $resarray = $utils->executeCLI($command, $outfile); |
||
| 1065 | if ($resarray['result'] != '0') { |
||
| 1066 | $this->error = $resarray['error'] . ' ' . $resarray['output']; |
||
| 1067 | $this->errors[] = $this->error; |
||
| 1068 | } |
||
| 1069 | $result = ($resarray['result'] == 0) ? 1 : 0; |
||
| 1070 | if ($result < 0 && empty($this->errors)) { |
||
| 1071 | $this->error = $langs->trans("ErrorFailToGenerateFile", $FILENAMEDOCPDF); |
||
| 1072 | $this->errors[] = $this->error; |
||
| 1073 | } |
||
| 1074 | |||
| 1075 | chdir($currentdir); |
||
| 1076 | } else { |
||
| 1077 | $result = 0; |
||
| 1078 | } |
||
| 1079 | |||
| 1080 | if ($result > 0) { |
||
| 1081 | return 1; |
||
| 1082 | } else { |
||
| 1083 | $error++; |
||
| 1084 | } |
||
| 1085 | } else { |
||
| 1086 | $error++; |
||
| 1087 | $langs->load("errors"); |
||
| 1088 | $this->error = $langs->trans("ErrorCheckVersionIsDefined"); |
||
| 1089 | } |
||
| 1090 | |||
| 1091 | return -1; |
||
| 1092 | } |
||
| 1093 | |||
| 1094 | /** |
||
| 1095 | * Execute a CLI command. |
||
| 1096 | * |
||
| 1097 | * @param string $command Command line to execute. |
||
| 1098 | * Warning: The command line is sanitize by escapeshellcmd(), except if $noescapecommand set, so can't contains any redirection char '>'. Use param $redirectionfile if you need it. |
||
| 1099 | * @param string $outputfile A path for an output file (used only when method is 2). For example: $conf->admin->dir_temp.'/out.tmp'; |
||
| 1100 | * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method |
||
| 1101 | * @param string $redirectionfile If defined, a redirection of output to this file is added. |
||
| 1102 | * @param int $noescapecommand 1=Do not escape command. Warning: Using this parameter needs you already have sanitized the $command parameter. If not, it will lead to security vulnerability. |
||
| 1103 | * This parameter is provided for backward compatibility with external modules. Always use 0 in core. |
||
| 1104 | * @param string $redirectionfileerr If defined, a redirection of error is added to this file instead of to channel 1. |
||
| 1105 | * @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK. |
||
| 1106 | */ |
||
| 1107 | public function executeCLI($command, $outputfile, $execmethod = 0, $redirectionfile = null, $noescapecommand = 0, $redirectionfileerr = null) |
||
| 1108 | { |
||
| 1109 | global $conf, $langs; |
||
| 1110 | |||
| 1111 | $result = 0; |
||
| 1112 | $output = ''; |
||
| 1113 | $error = ''; |
||
| 1114 | |||
| 1115 | if (empty($noescapecommand)) { |
||
| 1116 | $command = escapeshellcmd($command); |
||
| 1117 | } |
||
| 1118 | |||
| 1119 | if ($redirectionfile) { |
||
| 1120 | $command .= " > " . dol_sanitizePathName($redirectionfile); |
||
| 1121 | } |
||
| 1122 | |||
| 1123 | if ($redirectionfileerr && ($redirectionfileerr != $redirectionfile)) { |
||
| 1124 | // If we ask a redirect of stderr on a given file not already used for stdout |
||
| 1125 | $command .= " 2> " . dol_sanitizePathName($redirectionfileerr); |
||
| 1126 | } else { |
||
| 1127 | $command .= " 2>&1"; |
||
| 1128 | } |
||
| 1129 | |||
| 1130 | if (getDolGlobalString('MAIN_EXEC_USE_POPEN')) { |
||
| 1131 | $execmethod = getDolGlobalString('MAIN_EXEC_USE_POPEN'); |
||
| 1132 | } |
||
| 1133 | if (empty($execmethod)) { |
||
| 1134 | $execmethod = 1; |
||
| 1135 | } |
||
| 1136 | //$execmethod=1; |
||
| 1137 | dol_syslog("Utils::executeCLI execmethod=" . $execmethod . " command=" . $command, LOG_DEBUG); |
||
| 1138 | $output_arr = array(); |
||
| 1139 | |||
| 1140 | if ($execmethod == 1) { |
||
| 1141 | $retval = null; |
||
| 1142 | exec($command, $output_arr, $retval); |
||
| 1143 | $result = $retval; |
||
| 1144 | if ($retval != 0) { |
||
| 1145 | $langs->load("errors"); |
||
| 1146 | dol_syslog("Utils::executeCLI retval after exec=" . $retval, LOG_ERR); |
||
| 1147 | $error = 'Error ' . $retval; |
||
| 1148 | } |
||
| 1149 | } |
||
| 1150 | if ($execmethod == 2) { // With this method, there is no way to get the return code, only output |
||
| 1151 | $handle = fopen($outputfile, 'w+b'); |
||
| 1152 | if ($handle) { |
||
| 1153 | dol_syslog("Utils::executeCLI run command " . $command); |
||
| 1154 | $handlein = popen($command, 'r'); |
||
| 1155 | while (!feof($handlein)) { |
||
| 1156 | $read = fgets($handlein); |
||
| 1157 | fwrite($handle, $read); |
||
| 1158 | $output_arr[] = $read; |
||
| 1159 | } |
||
| 1160 | pclose($handlein); |
||
| 1161 | fclose($handle); |
||
| 1162 | } |
||
| 1163 | dolChmod($outputfile); |
||
| 1164 | } |
||
| 1165 | |||
| 1166 | // Update with result |
||
| 1167 | if (is_array($output_arr) && count($output_arr) > 0) { |
||
| 1168 | foreach ($output_arr as $val) { |
||
| 1169 | $output .= $val . ($execmethod == 2 ? '' : "\n"); |
||
| 1170 | } |
||
| 1171 | } |
||
| 1172 | |||
| 1173 | dol_syslog("Utils::executeCLI result=" . $result . " output=" . $output . " error=" . $error, LOG_DEBUG); |
||
| 1174 | |||
| 1175 | return array('result' => $result, 'output' => $output, 'error' => $error); |
||
| 1176 | } |
||
| 1177 | |||
| 1178 | /** |
||
| 1179 | * This saves syslog files and compresses older ones. |
||
| 1180 | * Nb of archive to keep is defined into $conf->global->SYSLOG_FILE_SAVES |
||
| 1181 | * CAN BE A CRON TASK |
||
| 1182 | * |
||
| 1183 | * @return int 0 if OK, < 0 if KO |
||
| 1184 | */ |
||
| 1185 | public function compressSyslogs() |
||
| 1186 | { |
||
| 1187 | global $conf; |
||
| 1188 | |||
| 1189 | if (empty($conf->loghandlers['mod_syslog_file'])) { // File Syslog disabled |
||
| 1190 | return 0; |
||
| 1191 | } |
||
| 1192 | |||
| 1193 | if (!function_exists('gzopen')) { |
||
| 1194 | $this->error = 'Support for gzopen not available in this PHP'; |
||
| 1195 | return -1; |
||
| 1196 | } |
||
| 1197 | |||
| 1198 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; |
||
| 1199 | |||
| 1200 | $nbSaves = intval(getDolGlobalString('SYSLOG_FILE_SAVES', 10)); |
||
| 1201 | |||
| 1202 | if (!getDolGlobalString('SYSLOG_FILE')) { |
||
| 1203 | $mainlogdir = DOL_DATA_ROOT; |
||
| 1204 | $mainlog = 'alixar.log'; |
||
| 1205 | } else { |
||
| 1206 | $mainlogfull = str_replace('DOL_DATA_ROOT', DOL_DATA_ROOT, $conf->global->SYSLOG_FILE); |
||
| 1207 | $mainlogdir = dirname($mainlogfull); |
||
| 1208 | $mainlog = basename($mainlogfull); |
||
| 1209 | } |
||
| 1210 | |||
| 1211 | $tabfiles = dol_dir_list(DOL_DATA_ROOT, 'files', 0, '^(dolibarr_.+|odt2pdf)\.log$'); // Also handle other log files like dolibarr_install.log |
||
| 1212 | $tabfiles[] = array('name' => $mainlog, 'path' => $mainlogdir); |
||
| 1213 | |||
| 1214 | foreach ($tabfiles as $file) { |
||
| 1215 | $logname = $file['name']; |
||
| 1216 | $logpath = $file['path']; |
||
| 1217 | |||
| 1218 | if (dol_is_file($logpath . '/' . $logname) && dol_filesize($logpath . '/' . $logname) > 0) { // If log file exists and is not empty |
||
| 1219 | // Handle already compressed files to rename them and add +1 |
||
| 1220 | |||
| 1221 | $filter = '^' . preg_quote($logname, '/') . '\.([0-9]+)\.gz$'; |
||
| 1222 | |||
| 1223 | $gzfilestmp = dol_dir_list($logpath, 'files', 0, $filter); |
||
| 1224 | $gzfiles = array(); |
||
| 1225 | |||
| 1226 | foreach ($gzfilestmp as $gzfile) { |
||
| 1227 | $tabmatches = array(); |
||
| 1228 | preg_match('/' . $filter . '/i', $gzfile['name'], $tabmatches); |
||
| 1229 | |||
| 1230 | $numsave = intval($tabmatches[1]); |
||
| 1231 | |||
| 1232 | $gzfiles[$numsave] = $gzfile; |
||
| 1233 | } |
||
| 1234 | |||
| 1235 | krsort($gzfiles, SORT_NUMERIC); |
||
| 1236 | |||
| 1237 | foreach ($gzfiles as $numsave => $dummy) { |
||
| 1238 | if (dol_is_file($logpath . '/' . $logname . '.' . ($numsave + 1) . '.gz')) { |
||
| 1239 | return -2; |
||
| 1240 | } |
||
| 1241 | |||
| 1242 | if ($numsave >= $nbSaves) { |
||
| 1243 | dol_delete_file($logpath . '/' . $logname . '.' . $numsave . '.gz', 0, 0, 0, null, false, 0); |
||
| 1244 | } else { |
||
| 1245 | dol_move($logpath . '/' . $logname . '.' . $numsave . '.gz', $logpath . '/' . $logname . '.' . ($numsave + 1) . '.gz', 0, 1, 0, 0); |
||
| 1246 | } |
||
| 1247 | } |
||
| 1248 | |||
| 1249 | // Compress current file and recreate it |
||
| 1250 | |||
| 1251 | if ($nbSaves > 0) { // If $nbSaves is 1, we keep 1 archive .gz file, If 2, we keep 2 .gz files |
||
| 1252 | $gzfilehandle = gzopen($logpath . '/' . $logname . '.1.gz', 'wb9'); |
||
| 1253 | |||
| 1254 | if (empty($gzfilehandle)) { |
||
| 1255 | $this->error = 'Failted to open file ' . $logpath . '/' . $logname . '.1.gz'; |
||
| 1256 | return -3; |
||
| 1257 | } |
||
| 1258 | |||
| 1259 | $sourcehandle = fopen($logpath . '/' . $logname, 'r'); |
||
| 1260 | |||
| 1261 | if (empty($sourcehandle)) { |
||
| 1262 | $this->error = 'Failed to open file ' . $logpath . '/' . $logname; |
||
| 1263 | return -4; |
||
| 1264 | } |
||
| 1265 | |||
| 1266 | while (!feof($sourcehandle)) { |
||
| 1267 | gzwrite($gzfilehandle, fread($sourcehandle, 512 * 1024)); // Read 512 kB at a time |
||
| 1268 | } |
||
| 1269 | |||
| 1270 | fclose($sourcehandle); |
||
| 1271 | gzclose($gzfilehandle); |
||
| 1272 | |||
| 1273 | dolChmod($logpath . '/' . $logname . '.1.gz'); |
||
| 1274 | } |
||
| 1275 | |||
| 1276 | dol_delete_file($logpath . '/' . $logname, 0, 0, 0, null, false, 0); |
||
| 1277 | |||
| 1278 | // Create empty file |
||
| 1279 | $newlog = fopen($logpath . '/' . $logname, 'a+'); |
||
| 1280 | fclose($newlog); |
||
| 1281 | |||
| 1282 | //var_dump($logpath.'/'.$logname." - ".octdec(empty($conf->global->MAIN_UMASK)?'0664':$conf->global->MAIN_UMASK)); |
||
| 1283 | dolChmod($logpath . '/' . $logname); |
||
| 1284 | } |
||
| 1285 | } |
||
| 1286 | |||
| 1287 | $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES=' . $nbSaves . ' files) done.'; |
||
| 1288 | return 0; |
||
| 1289 | } |
||
| 1290 | |||
| 1291 | /** |
||
| 1292 | * Make a send last backup of database or fil in param |
||
| 1293 | * CAN BE A CRON TASK |
||
| 1294 | * |
||
| 1295 | * @param string $sendto Recipients emails |
||
| 1296 | * @param string $from Sender email |
||
| 1297 | * @param string $subject Topic/Subject of mail |
||
| 1298 | * @param string $message Message |
||
| 1299 | * @param string $filename List of files to attach (full path of filename on file system) |
||
| 1300 | * @param string $filter Filter file send |
||
| 1301 | * @param int $sizelimit Limit size to send file |
||
| 1302 | * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) |
||
| 1303 | */ |
||
| 1304 | public function sendBackup($sendto = '', $from = '', $subject = '', $message = '', $filename = '', $filter = '', $sizelimit = 100000000) |
||
| 1404 | } |
||
| 1405 | } |
||
| 1406 | |||
| 1407 | /** |
||
| 1408 | * Clean unfinished cronjob in processing when pid is no longer present in the system |
||
| 1409 | * CAN BE A CRON TASK |
||
| 1410 | * |
||
| 1411 | * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) |
||
| 1412 | * @throws Exception |
||
| 1413 | */ |
||
| 1414 | public function cleanUnfinishedCronjob() |
||
| 1475 | } |
||
| 1476 | } |
||
| 1477 |