SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/Export.php

  1. <?php
  2. /*
  3.  * Copyright (C) 2017 Karmabunny Pty Ltd.
  4.  *
  5.  * This file is a part of SproutCMS.
  6.  *
  7.  * SproutCMS is free software: you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation, either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * For more information, visit <http://getsproutcms.com>.
  12.  */
  13.  
  14. namespace Sprout\Helpers;
  15.  
  16. class Export
  17. {
  18. private $tables = array();
  19. private $generated_files = array();
  20. private $filename_prefix = '';
  21. private $dbms = null;
  22. private $file_size = 0;
  23. private $file_idx = 0;
  24. private $hdr = '';
  25.  
  26. public $split_table = false;
  27. public $split_size = 0;
  28.  
  29.  
  30. public function addTable(ExportTable $table)
  31. {
  32. $this->tables[] = $table;
  33. }
  34.  
  35. public function getGeneratedFiles()
  36. {
  37. return $this->generated_files;
  38. }
  39.  
  40. public function setFilenamePrefix($val)
  41. {
  42. $this->filename_prefix = $val;
  43. }
  44.  
  45. public function setDbms($dbms)
  46. {
  47. $this->dbms = $dbms;
  48. }
  49.  
  50.  
  51. /**
  52.   * Exports the specified tables to an SQL file
  53.   * @tag maybe-error-not-mysql
  54.   **/
  55. public function exportSql()
  56. {
  57.  
  58. $this->hdr = $this->dbms->hdr();
  59.  
  60. if (! $this->split_table) {
  61. $next_filename = $this->createNextFilename(null, '.sql');
  62. $curr_file = fopen($this->filename_prefix . $next_filename, 'w');
  63. fwrite($curr_file, $this->hdr);
  64. $this->generated_files[] = $next_filename;
  65.  
  66. $this->file_size = 0;
  67. $this->file_idx = 1;
  68. }
  69.  
  70.  
  71. foreach ($this->tables as $table_def) {
  72.  
  73. // If per-table splitting is on, open a new file
  74. if ($this->split_table) {
  75. $next_filename = $this->createNextFilename($table_def->name, '.sql');
  76. $curr_file = fopen($this->filename_prefix . $next_filename, 'w');
  77. fwrite($curr_file, $this->hdr);
  78. $this->generated_files[] = $next_filename;
  79.  
  80. $this->file_size = 0;
  81. $this->file_idx = 1;
  82. }
  83.  
  84. // If dropping is on, add the query
  85. if ($table_def->drop) {
  86. $str = $this->dbms->drop($table_def);
  87.  
  88. $next_filename = $this->createNextFilename($table_def->name, '.sql');
  89. $curr_file = $this->sizeCheckWrite($curr_file, $str, $next_filename);
  90. }
  91.  
  92. // If structure is on, add the query
  93. if ($table_def->structure) {
  94. $str = $this->dbms->structure($table_def);
  95.  
  96. $next_filename = $this->createNextFilename($table_def->name, '.sql');
  97. $curr_file = $this->sizeCheckWrite($curr_file, $str, $next_filename);
  98. }
  99.  
  100. // Dump data (CSV file)
  101. if ($table_def->data == ExportTableSQL::DATA_CSV) {
  102. $q = "SELECT * FROM `{$table_def->name}`";
  103. if ($table_def->where) $q .= " WHERE {$table_def->where}";
  104.  
  105. $res = Pdb::query($q, [], 'pdo');
  106. $csv_data = QueryTo::csv($res);
  107.  
  108. file_put_contents($this->filename_prefix . $table_def->name . '.csv', $csv_data);
  109. $this->generated_files[] = $table_def->name . '.csv';
  110.  
  111.  
  112. // Dump data (inserts, updates, insert..updates
  113. } else if ($table_def->data != ExportTableSQL::DATA_NONE) {
  114. $q = "SELECT * FROM `{$table_def->name}`";
  115. if ($table_def->where) $q .= " WHERE {$table_def->where}";
  116.  
  117. $res = Pdb::query($q, [], 'pdo');
  118.  
  119. $pk_names = $this->getPkColNames($table_def->name);
  120.  
  121. foreach ($res as $row) {
  122. switch ($table_def->data) {
  123. case ExportTableSQL::DATA_INSERT:
  124. // insert query
  125. $str = $this->dbms->insert($table_def, $row);
  126. break;
  127.  
  128. case ExportTableSQL::DATA_UPDATE:
  129. // update query
  130. $str = $this->dbms->update($table_def, $pk_names, $row);
  131. break;
  132.  
  133. case ExportTableSQL::DATA_BOTH:
  134. // insert...update
  135. $str = $this->dbms->insertUpdate($table_def, $pk_names, $row);
  136. break;
  137.  
  138. }
  139.  
  140. $next_filename = $this->createNextFilename($table_def->name, '.sql');
  141. $curr_file = $this->sizeCheckWrite($curr_file, $str, $next_filename);
  142. }
  143.  
  144. $res->closeCursor();
  145. }
  146.  
  147. fwrite($curr_file, "\n");
  148.  
  149. // If per-table splitting is on, open a new file
  150. if ($this->split_table) {
  151. fclose($curr_file);
  152. }
  153. }
  154.  
  155. if (! $this->split_table) {
  156. fclose($curr_file);
  157. }
  158. }
  159.  
  160.  
  161. /**
  162.   * Creates the filename which should be used for the next file if the current file is deemed to be too full
  163.   **/
  164. private function createNextFilename($table_name, $ext)
  165. {
  166. return ($this->split_table ? $table_name : 'all') . '-' . $this->file_idx . $ext;
  167. }
  168.  
  169.  
  170. /**
  171.   * Gets the column names for the primary key
  172.   * @tag maybe-error-not-mysql
  173.   **/
  174. private function getPkColNames($table)
  175. {
  176. $q = "SHOW COLUMNS FROM `{$table}`";
  177. $res = Pdb::query($q, [], 'pdo');
  178.  
  179. $columns = array();
  180. foreach ($res as $row) {
  181. if ($row['Key'] == 'PRI') $columns[] = $row['Field'];
  182. }
  183. $res->closeCursor();
  184.  
  185. return $columns;
  186. }
  187.  
  188.  
  189. /**
  190.   * Writes data to a file, if allowed by the file size restrictions.
  191.   * If not, creates a new file.
  192.   **/
  193. private function sizeCheckWrite($handle, $str, $next_filename)
  194. {
  195. $this->file_size += strlen($str);
  196.  
  197. if ($this->split_size != 0 and $this->file_size > $this->split_size) {
  198. fclose($handle);
  199.  
  200. $this->file_size = strlen($str);
  201. $this->file_idx++;
  202.  
  203. $handle = fopen($this->filename_prefix . $next_filename, 'w');
  204. fwrite($handle, $this->hdr);
  205. $this->generated_files[] = $next_filename;
  206. }
  207.  
  208. fwrite($handle, $str);
  209.  
  210. return $handle;
  211. }
  212.  
  213.  
  214. /**
  215.   * Loads all of the generated export files into a ZIP file
  216.   **/
  217. public function buildArchive($name)
  218. {
  219. $arch = new Archive('zip');
  220.  
  221. foreach ($this->generated_files as $filename) {
  222. $arch->add($this->filename_prefix . $filename, $filename);
  223. }
  224.  
  225. $arch->save($this->filename_prefix . $name);
  226. $this->generated_files = array($name);
  227. }
  228.  
  229.  
  230. }
  231.  
  232.  
  233.