5 * This should allow you to dump a series of data, so it could be restored later...
6 * The format will be an SQL file...
9 * php index.php Admin/Dump --table=Project --where="id=123"
10 * --dump-dir=/directory_to_put_sql+shell files
12 * outputs list of generated files.
15 * {DATE}.sql - the recreate sql including all dependancies, run with mysql DB -f < ....
16 * {DATE}.restore.sh - shell script to recreate files that where removed (excluding thumgs)
19 * {DATE}.copy.sh - shell script that backs up all the related files.
22 * {DATE}.delete.sql - the delete data sql.
23 * {DATE}.delete.sh - shell script to delete the files related to these records
26 * Basically it has to output all the records and their dependants. (parent and children)
28 * Then when deleting it deletes record + children..
31 * Each ouput is simple insert statement..
34 * TODO - handle Images table (or similar) where we use tablename=XXXX, tid=.... etc..
39 * DataObjects->archivePaths() - returns array ( sourcedirectory, remainder of path to dependant file )
40 * DataObjects->listThumbs() - returns array ( list of full path to thumbnail urls. )
49 require_once 'Pman.php';
51 class Pman_Admin_Export extends Pman_Admin_Dump {
53 static $cli_desc = "Dump database and related files so it could be restored later..";
59 if (!HTML_FlexyFramework::get()->cli) {
60 die("Access only permitted from cli");
65 var $deps = array(); // list of dependants
66 var $out = array(); // list of created sql/shell scripts.
72 ini_set('memory_limit', '256M'); // we need alot of memory
75 $argv = $_SERVER['argv'];
79 $opts = explode(',', 'table==,where==,dump-dir==,debug=');
80 require_once 'Console/Getopt.php';
81 $go = Console_Getopt::getopt2($argv, '', $opts );
86 foreach($go[0] as $ar) {
87 $args[substr($ar[0],2)] = $ar[1];
90 foreach($opts as $req) {
91 if (substr($req,-2, 2) != '==') { // skip optional arguments
94 if (empty($args[substr($req,0, -2)])) {
95 $errs[] = "--".substr($req,0, -2) . ' is required';
99 die(print_R($errs,true));
101 if (!empty($args['debug'])) {
102 DB_DataObject::debugLevel($args['debug']);
105 $this->out = array();
115 $this->discoverChildren($this->args['table'], $this->args['where'], true);
116 //print_R($this->deletes);
117 //print_r($this->dumps);
120 $this->discover($this->args['table'], $this->args['where'], true);
123 if (!file_exists($args['dump-dir'])) {
124 mkdir($args['dump-dir'], 0777, true);
134 echo "GENERATED FILES:\n";
136 echo " ". implode("\n ", $this->out). "\n";
145 var $deletes = array(); // TABLE => [key] => TRUE|FALSE
146 var $dumps = array(); // TABLE => [key] => TRUE|FALSE - if it's been scanned..
147 var $dscan = array(); // TABLE:COL => [value => TRUE|FALSE] - if its been scanned..
148 var $childfiles = array(); // array of [ 'sourcedirectory' , 'subdirectory(s) and filename' ]
149 var $childthumbs = array(); // array of [ 'filename', 'filename' ,......]
150 var $filesize = 0; // size of files to be saved. (not total deletd..)
151 var $filetotal = 0; // number of distinct files to be saved (not total deleted)
154 * a) what depends on it (eg. child elements) - which will be deleted.
155 * b) what it depends on it (eg. parent elements) - which will be dumped..
160 function generateDelete() {
161 $target = $this->args['dump-dir'] .'/'. date('Y-m-d').'.delete.sql';
162 $this->out[] = $target;
163 $fh = fopen($target, 'w');
167 foreach($this->deletes as $tbl=>$ar) {
169 $do = DB_DataObject::factory($tbl);
170 $tbl = $do->tableName();
173 $do->whereAddIn($keys[0] , array_keys($ar), 'int');
175 $archivePaths = method_exists($do,'archivePaths');
176 $listThumbs = method_exists($do,'listThumbs');
177 while ($do->fetch()) {
180 $ct = $do->archivePaths();
182 $this->childfiles[] = $ct;
186 $ct = $do->listThumbs();
188 $this->childthumbs[] = $ct;
193 fwrite($fh, "DELETE FROM `$tbl` WHERE `$key` = $id;\n"); // we assume id's and nice column names...
199 function generateShell() {
201 if (empty($this->childfiles) && empty($this->childthumbs)) {
204 $target = $this->args['dump-dir'] .'/'. date('Y-m-d').'.copy.sh';
205 $this->out[] = $target;
206 $fh = fopen($target, 'w');
208 $target = $this->args['dump-dir'] .'/'. date('Y-m-d').'.delete.sh';
209 $this->out[] = $target;
210 $fh2 = fopen($target, 'w');
212 $target = $this->args['dump-dir'] .'/'. date('Y-m-d').'.restore.sh';
213 $this->out[] = $target;
214 $fh3 = fopen($target, 'w');
219 foreach($this->childfiles as $v) {
221 if (isset($done[$v[1]])) {
227 $this->filesize += filesize($v[0].'/'.$v[1]);
229 $fdir = dirname($this->args['dump-dir'] .'/'.$v[1]);
230 if (!isset($donedir[$fdir])) {
231 fwrite($fh,"mkdir -p " . escapeshellarg(dirname($this->args['dump-dir'] .'/'.$v[1])) ."\n" );
233 fwrite($fh,"cp " . escapeshellarg($v[0].'/'.$v[1]) . ' ' . escapeshellarg($this->args['dump-dir'] .'/'.$v[1]) ."\n" );
234 if (!isset($donedir[$fdir])) {
235 fwrite($fh3,"mkdir -p " . escapeshellarg(dirname($v[0].'/'.$v[1])) ."\n" );
237 $donedir[$fdir] = true;
239 fwrite($fh3,"cp " . escapeshellarg($this->args['dump-dir'] .'/'.$v[1]) . ' ' . escapeshellarg($v[0].'/'.$v[1]) . "\n" );
240 fwrite($fh2,"rm " . escapeshellarg($v[0].'/'.$v[1]) ."\n" );
243 fclose($fh3); // restore does not need to bother with thumbnails.
247 foreach($this->childthumbs as $v) {
249 fwrite($fh2,"rm " . escapeshellarg($vv). "\n");
255 function generateInsert()
257 $target = $this->args['dump-dir'] .'/'. date('Y-m-d').'.sql';
258 $this->out[] = $target;
259 $fh = fopen($target,'w');
263 foreach($this->dumps as $tbl => $ar) {
267 $do = DB_DataObject::factory($tbl);
271 $do->whereAddIn($keys[0] , array_keys($ar), 'int');
273 while ($do->fetch()) {
274 fwrite($fh,$this->toInsert($do));
287 * toInsert - does not handle NULLS...
289 function toInsert($do)
291 $kcol = array_shift($do->keys());
293 // for auto_inc column we need to use a 'set argument'...
294 $items = $do->table();
301 $table = $do->tableName();
304 foreach( $items as $k=>$v)
311 $leftq .= '`' . $k . '`';
316 if ($v & DB_DATAOBJECT_STR) {
317 $rightq .= $do->_quote((string) (
318 ($v & DB_DATAOBJECT_BOOL) ?
319 // this is thanks to the braindead idea of postgres to
320 // use t/f for boolean.
321 (($do->$k === 'f') ? 0 : (int)(bool) $do->$k) :
326 if (is_numeric($do->$k)) {
327 $rightq .=" {$do->$k} ";
330 $rightq .= ' ' . intval($do->$k) . ' ';
333 return "INSERT INTO `{$table}` ($leftq) VALUES ($rightq);\n";