content.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Tom Needham
  6. * @copyright 2012 Tom Needham tom@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * provides methods to add and access data from the migration
  24. */
  25. class OC_Migration_Content{
  26. private $zip=false;
  27. // Holds the MDB2 object
  28. private $db=null;
  29. // Holds an array of tmpfiles to delete after zip creation
  30. private $tmpfiles=array();
  31. /**
  32. * @brief sets up the
  33. * @param $zip ZipArchive object
  34. * @param optional $db a MDB2 database object (required for exporttype user)
  35. * @return bool
  36. */
  37. public function __construct( $zip, $db=null ) {
  38. $this->zip = $zip;
  39. $this->db = $db;
  40. }
  41. // @brief prepares the db
  42. // @param $query the sql query to prepare
  43. public function prepare( $query ) {
  44. // Only add database to tmpfiles if actually used
  45. if( !is_null( $this->db ) ) {
  46. // Get db path
  47. $db = $this->db->getDatabase();
  48. if(!in_array($db, $this->tmpfiles)) {
  49. $this->tmpfiles[] = $db;
  50. }
  51. }
  52. // Optimize the query
  53. $query = $this->processQuery( $query );
  54. // Optimize the query
  55. $query = $this->db->prepare( $query );
  56. // Die if we have an error (error means: bad query, not 0 results!)
  57. if( PEAR::isError( $query ) ) {
  58. $entry = 'DB Error: "'.$query->getMessage().'"<br />';
  59. $entry .= 'Offending command was: '.$query.'<br />';
  60. OC_Log::write( 'migration', $entry, OC_Log::FATAL );
  61. return false;
  62. } else {
  63. return $query;
  64. }
  65. }
  66. /**
  67. * @brief processes the db query
  68. * @param $query the query to process
  69. * @return string of processed query
  70. */
  71. private function processQuery( $query ) {
  72. $query = str_replace( '`', '\'', $query );
  73. $query = str_replace( 'NOW()', 'datetime(\'now\')', $query );
  74. $query = str_replace( 'now()', 'datetime(\'now\')', $query );
  75. // remove table prefixes
  76. $query = str_replace( '*PREFIX*', '', $query );
  77. return $query;
  78. }
  79. /**
  80. * @brief copys rows to migration.db from the main database
  81. * @param $options array of options.
  82. * @return bool
  83. */
  84. public function copyRows( $options ) {
  85. if( !array_key_exists( 'table', $options ) ) {
  86. return false;
  87. }
  88. $return = array();
  89. // Need to include 'where' in the query?
  90. if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ) {
  91. // If only one matchval, create an array
  92. if(!is_array($options['matchval'])) {
  93. $options['matchval'] = array( $options['matchval'] );
  94. }
  95. foreach( $options['matchval'] as $matchval ) {
  96. // Run the query for this match value (where x = y value)
  97. $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '` WHERE `' . $options['matchcol'] . '` = ?';
  98. $query = OC_DB::prepare( $sql );
  99. $results = $query->execute( array( $matchval ) );
  100. $newreturns = $this->insertData( $results, $options );
  101. $return = array_merge( $return, $newreturns );
  102. }
  103. } else {
  104. // Just get everything
  105. $sql = 'SELECT * FROM `*PREFIX*' . $options['table'] . '`';
  106. $query = OC_DB::prepare( $sql );
  107. $results = $query->execute();
  108. $return = $this->insertData( $results, $options );
  109. }
  110. return $return;
  111. }
  112. /**
  113. * @brief saves a sql data set into migration.db
  114. * @param $data a sql data set returned from self::prepare()->query()
  115. * @param $options array of copyRows options
  116. * @return void
  117. */
  118. private function insertData( $data, $options ) {
  119. $return = array();
  120. // Foreach row of data to insert
  121. while( $row = $data->fetchRow() ) {
  122. // Now save all this to the migration.db
  123. foreach($row as $field=>$value) {
  124. $fields[] = $field;
  125. $values[] = $value;
  126. }
  127. // Generate some sql
  128. $sql = "INSERT INTO `" . $options['table'] . '` ( `';
  129. $fieldssql = implode( '`, `', $fields );
  130. $sql .= $fieldssql . "` ) VALUES( ";
  131. $valuessql = substr( str_repeat( '?, ', count( $fields ) ), 0, -2 );
  132. $sql .= $valuessql . " )";
  133. // Make the query
  134. $query = $this->prepare( $sql );
  135. if( !$query ) {
  136. OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL );
  137. return false;
  138. exit();
  139. } else {
  140. $query->execute( $values );
  141. // Do we need to return some values?
  142. if( array_key_exists( 'idcol', $options ) ) {
  143. // Yes we do
  144. $return[] = $row[$options['idcol']];
  145. } else {
  146. // Take a guess and return the first field :)
  147. $return[] = reset($row);
  148. }
  149. }
  150. $fields = '';
  151. $values = '';
  152. }
  153. return $return;
  154. }
  155. /**
  156. * @brief adds a directory to the zip object
  157. * @param $dir string path of the directory to add
  158. * @param $recursive bool
  159. * @param $internaldir string path of folder to add dir to in zip
  160. * @return bool
  161. */
  162. public function addDir( $dir, $recursive=true, $internaldir='' ) {
  163. $dirname = basename($dir);
  164. $this->zip->addEmptyDir($internaldir . $dirname);
  165. $internaldir.=$dirname.='/';
  166. if( !file_exists( $dir ) ) {
  167. return false;
  168. }
  169. $dirhandle = opendir($dir);
  170. if(is_resource($dirhandle)) {
  171. while (false !== ( $file = readdir($dirhandle))) {
  172. if (( $file != '.' ) && ( $file != '..' )) {
  173. if (is_dir($dir . '/' . $file) && $recursive) {
  174. $this->addDir($dir . '/' . $file, $recursive, $internaldir);
  175. } elseif (is_file($dir . '/' . $file)) {
  176. $this->zip->addFile($dir . '/' . $file, $internaldir . $file);
  177. }
  178. }
  179. }
  180. closedir($dirhandle);
  181. } else {
  182. OC_Log::write('admin_export', "Was not able to open directory: " . $dir, OC_Log::ERROR);
  183. return false;
  184. }
  185. return true;
  186. }
  187. /**
  188. * @brief adds a file to the zip from a given string
  189. * @param $data string of data to add
  190. * @param $path the relative path inside of the zip to save the file to
  191. * @return bool
  192. */
  193. public function addFromString( $data, $path ) {
  194. // Create a temp file
  195. $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' );
  196. $this->tmpfiles[] = $file;
  197. if( !file_put_contents( $file, $data ) ) {
  198. OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR );
  199. return false;
  200. }
  201. // Add file to the zip
  202. $this->zip->addFile( $file, $path );
  203. return true;
  204. }
  205. /**
  206. * @brief closes the zip, removes temp files
  207. * @return bool
  208. */
  209. public function finish() {
  210. if( !$this->zip->close() ) {
  211. OC_Log::write( 'migration',
  212. 'Failed to write the zip file with error: '.$this->zip->getStatusString(),
  213. OC_Log::ERROR );
  214. return false;
  215. }
  216. $this->cleanup();
  217. return true;
  218. }
  219. /**
  220. * @brief cleans up after the zip
  221. */
  222. private function cleanup() {
  223. // Delete tmp files
  224. foreach($this->tmpfiles as $i) {
  225. unlink( $i );
  226. }
  227. }
  228. }