1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8namespace Tiki\Command; 9 10use Symfony\Component\Console\Command\Command; 11use Symfony\Component\Console\Input\InputArgument; 12use Symfony\Component\Console\Input\InputInterface; 13use Symfony\Component\Console\Input\InputOption; 14use Symfony\Component\Console\Output\OutputInterface; 15 16class BackupDBCommand extends Command 17{ 18 protected function configure() 19 { 20 $this 21 ->setName('database:backup') 22 ->setDescription('Create a database backup (with mysqldump)') 23 ->addArgument( 24 'path', 25 InputArgument::REQUIRED, 26 'Path to save backup (relative to console.php, or absolute)' 27 ) 28 ->addArgument( 29 'dateFormat', 30 InputArgument::OPTIONAL, 31 'Format to use for the date part of the backup file. Defaults to "Y-m-d_H-i-s" and uses the PHP date function format' 32 ) 33 ; 34 } 35 36 protected function execute(InputInterface $input, OutputInterface $output) 37 { 38 $path = $input->getArgument('path'); 39 if (substr($path, -1) == '/') { 40 $path = substr($path, 0, strlen($path) - 1); 41 } 42 43 if (! is_dir($path)) { 44 $output->writeln('<error>Error: Provided path not found</error>'); 45 return; 46 } 47 48 $local = \TikiInit::getCredentialsFile(); 49 if (! is_readable($local)) { 50 $output->writeln('<error>Error: "' . $local . '" not readable.</error>'); 51 return; 52 } 53 54 $dateFormat = $input->getArgument('dateFormat'); 55 if (! $dateFormat) { 56 $dateFormat = 'Y-m-d_H-i-s'; 57 } 58 59 $user_tiki = $pass_tiki = $host_tiki = $dbs_tiki = ''; 60 61 require $local; 62 63 $args = []; 64 if ($user_tiki) { 65 $args[] = "-u" . escapeshellarg($user_tiki); 66 } 67 if ($pass_tiki) { 68 $args[] = "-p" . escapeshellarg($pass_tiki); 69 } 70 if ($host_tiki) { 71 $args[] = "-h" . escapeshellarg($host_tiki); 72 } 73 74 // Find out how many non-InnoDB tables exist in the schema 75 $db = \TikiDb::get(); 76 $query = "SELECT count(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '$dbs_tiki' AND engine <> 'InnoDB'"; 77 $numTables = $db->getOne($query); 78 79 if ($numTables === '0') { 80 $args[] = "--single-transaction"; 81 } else { 82 $dbOpenFilesLimit = 0; 83 $result = $db->fetchAll('SHOW GLOBAL VARIABLES LIKE "open_files_limit"'); 84 if (count($result) > 0) { 85 $dbOpenFilesLimit = (int)$result[0]['Value']; 86 } 87 if ($dbOpenFilesLimit > 0 && $dbOpenFilesLimit < 2000) { 88 // some distributions bring a lower limit of open files, so lock all tables during backup might fail the backup 89 $output->writeln('<info>Mysql database has open_files_limit=' . $dbOpenFilesLimit . ', skipping lock tables to avoid failing the backup</info>'); 90 } else { 91 $args[] = "--lock-tables"; 92 } 93 } 94 95 $args[] = $dbs_tiki; 96 97 $args = implode(' ', $args); 98 $outputFile = $path . '/' . $dbs_tiki . '_' . date($dateFormat) . '.sql.gz'; 99 $command = "mysqldump --quick --create-options --extended-insert $args | gzip -5 > " . escapeshellarg($outputFile); 100 exec($command); 101 $output->writeln('<comment>Database backup completed: ' . $outputFile . '</comment>'); 102 } 103} 104