|
@@ -0,0 +1,895 @@
|
|
|
+<?php
|
|
|
+/* *********************************************************************************** */
|
|
|
+/* 2023 code created by Eesger Toering / knoop.frl / geoarchive.eu */
|
|
|
+/* GitHub: https://github.com/mrAceT/nextcloud-S3-local-S3-migration */
|
|
|
+/* Like the work? You'll be surprised how much time goes into things like this.. */
|
|
|
+/* be my hero, support my work, */
|
|
|
+/* https://paypal.me/eesgertoering */
|
|
|
+/* https://www.geef.nl/en/donate?action=15544 */
|
|
|
+/* *********************************************************************************** */
|
|
|
+
|
|
|
+# best practice: run the script as the cloud-user!!
|
|
|
+# sudo -u apache php81 -d memory_limit=1024M /var/www/html/nextcloud/localtos3.php
|
|
|
+
|
|
|
+# runuser -u apache -- composer require aws/aws-sdk-php
|
|
|
+use Aws\S3\S3Client;
|
|
|
+
|
|
|
+# uncomment this for large file uploads (Amazon advises this voor 100Mb+ files)
|
|
|
+#use Aws\S3\MultipartUploader;
|
|
|
+#$MULTIPART_THRESHOLD = 500; #Megabytes
|
|
|
+
|
|
|
+echo "\n#########################################################################################".
|
|
|
+ "\n Migration tool for Nextcloud local to S3 version 0.35".
|
|
|
+ "\n".
|
|
|
+ "\n Reading config...";
|
|
|
+
|
|
|
+$PREVIEW_MAX_AGE = 0; // max age (days) of preview images (EXPERIMENTAL! 0 = no del)
|
|
|
+$PREVIEW_MAX_DEL = 0.005; // max amount of previews to delete at a time (when < 1 & > 0 => percentage! )..
|
|
|
+
|
|
|
+// Note: Preferably use absolute path without trailing directory separators
|
|
|
+$PATH_BASE = '/var/www/html/nextcloud'; // Path to the base of the main Nextcloud directory
|
|
|
+
|
|
|
+$PATH_NEXTCLOUD = $PATH_BASE; // Path of the public Nextcloud directory
|
|
|
+
|
|
|
+$PATH_BACKUP = $PATH_BASE.'/bak'; // Path for backup of MySQL database (you must create it yourself..)
|
|
|
+
|
|
|
+$OCC_BASE = 'php81 -d memory_limit=1024M '.$PATH_NEXTCLOUD.'/occ ';
|
|
|
+// don't forget this one --. (if you don't run the script as the 'clouduser', see first comment at the top)
|
|
|
+#$OCC_BASE = 'sudo -u apache php81 -d memory_limit=1024M '.$PATH_NEXTCLOUD.'/occ ';
|
|
|
+
|
|
|
+$TEST = '2'; //'admin';//'appdata_oczvcie123w4';
|
|
|
+// set to 0 for LIVE!!
|
|
|
+// set to 1 for all data : NO db modifications, with file modifications/uplaods/removal
|
|
|
+// set to user name for single user (migration) test
|
|
|
+// set to 2 for complete dry run
|
|
|
+
|
|
|
+$SET_MAINTENANCE = 1; // only in $TEST=0 Nextcloud will be put into maintenance mode
|
|
|
+// ONLY when migration is all done you can set this to 0 for the S3-consitancy checks
|
|
|
+
|
|
|
+$SHOWINFO = 1; // set to 0 to force much less info (while testing)
|
|
|
+
|
|
|
+$SQL_DUMP_USER = ''; // leave both empty if nextcloud user has enough rights..
|
|
|
+$SQL_DUMP_PASS = '';
|
|
|
+
|
|
|
+$CONFIG_OBJECTSTORE = dirname(__FILE__).'/storage.config.php';
|
|
|
+
|
|
|
+# It is probably wise to set the two vars below to '1' once, let the 'Nextcloud' do some checking..
|
|
|
+$DO_FILES_CLEAN = 0; // perform occ files:cleanup | can take a while on large accounts (should not be necessary but cannot hurt / not working while in maintenance.. )
|
|
|
+$DO_FILES_SCAN = 0; // perform occ files:scan --all | can take a while on large accounts (should not be necessary but cannot hurt / not working while in maintenance.. )
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\nSetting up local migration to S3 (sync)...\n";
|
|
|
+
|
|
|
+// Autoload
|
|
|
+require_once(dirname(__FILE__).'/vendor/autoload.php');
|
|
|
+
|
|
|
+echo "\nfirst load the nextcloud config...";
|
|
|
+include($PATH_NEXTCLOUD.'/config/config.php');
|
|
|
+if (!empty($CONFIG['objectstore'])) {
|
|
|
+ if ($CONFIG_OBJECTSTORE == $PATH_NEXTCLOUD.'/config/config.php') {
|
|
|
+ echo "\nS3 config found in \$PATH_NEXTCLOUD system config.php => same as \$CONFIG_OBJECTSTORE !";
|
|
|
+ } else {
|
|
|
+ echo "\nS3 config found in \$PATH_NEXTCLOUD system config.php => \$CONFIG_OBJECTSTORE not used! ($CONFIG_OBJECTSTORE)";
|
|
|
+ }
|
|
|
+ $CONFIG_OBJECTSTORE = ''; //no copy!
|
|
|
+} else {
|
|
|
+ echo "\nS3 NOT configured in config.php, using \$CONFIG_OBJECTSTORE";
|
|
|
+ if (is_string($CONFIG_OBJECTSTORE) && file_exists($CONFIG_OBJECTSTORE)) {
|
|
|
+ $CONFIG_MERGE = $CONFIG;
|
|
|
+ include($CONFIG_OBJECTSTORE);
|
|
|
+ $CONFIG = array_merge($CONFIG_MERGE,$CONFIG);
|
|
|
+ }
|
|
|
+ else if (is_array($CONFIG_OBJECTSTORE)) {
|
|
|
+ $CONFIG['objectstore'] = $CONFIG_OBJECTSTORE;
|
|
|
+ } else {
|
|
|
+ echo "\nERROR: var \$CONFIG_OBJECTSTORE is not configured (".gettype($CONFIG_OBJECTSTORE)." / $CONFIG_OBJECTSTORE)\n\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+}
|
|
|
+$PATH_DATA = preg_replace('/\/*$/','',$CONFIG['datadirectory']);
|
|
|
+
|
|
|
+echo "\nconnect to sql-database...";
|
|
|
+// Database setup
|
|
|
+$mysqli = new mysqli($CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpassword'], $CONFIG['dbname']);
|
|
|
+if ($CONFIG['mysql.utf8mb4']) {
|
|
|
+ $mysqli->set_charset('utf8mb4');
|
|
|
+}
|
|
|
+
|
|
|
+################################################################################ checks #
|
|
|
+$LOCAL_STORE_ID = 0;
|
|
|
+if ($result = $mysqli->query("SELECT * FROM `oc_storages` WHERE `id` = 'local::$PATH_DATA/'")) {
|
|
|
+ if ($result->num_rows>1) {
|
|
|
+ echo "\nERROR: Multiple 'local::$PATH_DATA', it's an accident waiting to happen!!\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+ else if ($result->num_rows == 1) {
|
|
|
+ echo "\nFOUND 'local::$PATH_DATA', good. ";
|
|
|
+ $row = $result->fetch_assoc();
|
|
|
+ $LOCAL_STORE_ID = $row['numeric_id']; // for creative rename command..
|
|
|
+ echo "\nThe local store id is:$LOCAL_STORE_ID";
|
|
|
+ } else {
|
|
|
+ echo "\nWARNING: no 'local::$PATH_DATA' found, therefor no sync local data > S3!\n";
|
|
|
+ }
|
|
|
+}
|
|
|
+$OBJECT_STORE_ID = 0;
|
|
|
+if ($result = $mysqli->query("SELECT * FROM `oc_storages` WHERE `id` LIKE 'object::store:amazon::".$CONFIG['objectstore']['arguments']['bucket']."'")) {
|
|
|
+ if ($result->num_rows>1) {
|
|
|
+ echo "\nMultiple 'object::store:amazon::".$CONFIG['objectstore']['arguments']['bucket']."' clean this up, it's an accident waiting to happen!!\n\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+ else if ($result->num_rows == 0) {
|
|
|
+ if (empty($CONFIG['objectstore'])) {
|
|
|
+ echo "\nERROR: No 'object::store:' & NO S3 storage defined\n\n";
|
|
|
+ die;
|
|
|
+ } else {
|
|
|
+ echo "\nNOTE: No 'object::store:' > S3 storage = defined\n\n";
|
|
|
+ echo "\n Upon migration local will be renamed to object::store";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ echo "\nFOUND 'object::store:amazon::".$CONFIG['objectstore']['arguments']['bucket']."', OK";
|
|
|
+ $row = $result->fetch_assoc();
|
|
|
+ $OBJECT_STORE_ID = $row['numeric_id']; // for creative rename command..
|
|
|
+ echo "\nThe object store id is:$OBJECT_STORE_ID";
|
|
|
+
|
|
|
+ $result = $mysqli->query("SELECT `fileid` FROM `oc_filecache` WHERE `storage` = ".$OBJECT_STORE_ID);
|
|
|
+ if ( $result->num_rows > 0 ) {
|
|
|
+ echo "\n\nWARNING: if this is for a full migration remove all data with `storage` = $OBJECT_STORE_ID in your `oc_filecache` !!!!\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+$result->free_result();
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n######################################################################################### ".$TEST;
|
|
|
+if (empty($TEST) ) {
|
|
|
+ echo "\n\nNOTE: THIS IS THE REAL THING!!\n";
|
|
|
+} else {
|
|
|
+ echo empty($TEST) ? '' : "\nWARNING: you are in test mode (".$TEST.")";
|
|
|
+}
|
|
|
+echo "\nBase init complete, continue?";
|
|
|
+$getLine = '';
|
|
|
+while ($getLine == ''): $getLine = fgets( fopen("php://stdin","r") ); endwhile;
|
|
|
+
|
|
|
+echo "\n######################################################################################### ";
|
|
|
+
|
|
|
+if ($DO_FILES_CLEAN) {
|
|
|
+ echo "\nRunning cleanup (should not be necessary but cannot hurt)";
|
|
|
+ echo occ($OCC_BASE,'files:cleanup');
|
|
|
+}
|
|
|
+if ($DO_FILES_SCAN) {
|
|
|
+ echo "\nRunning scan (should not be necessary but cannot hurt)";
|
|
|
+ echo occ($OCC_BASE,'files:scan --all');
|
|
|
+}
|
|
|
+
|
|
|
+if (empty($TEST)) {
|
|
|
+ if ($SET_MAINTENANCE) { // maintenance mode
|
|
|
+ $process = occ($OCC_BASE,'maintenance:mode --on');
|
|
|
+ echo $process;
|
|
|
+ if (strpos($process, "\nMaintenance mode") == 0
|
|
|
+ && strpos($process, 'Maintenance mode already enabled') == 0) {
|
|
|
+ echo " could not set.. ouput command: ".$process."\n\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+ }
|
|
|
+} else {
|
|
|
+ echo "\n\nNOTE: In TEST-mode, will not enter maintenance mode";
|
|
|
+}
|
|
|
+
|
|
|
+echo "\ndatabase backup...";
|
|
|
+if (!is_dir($PATH_BACKUP)) { echo "\$PATH_BACKUP folder does not exist\n"; die; }
|
|
|
+
|
|
|
+$process = shell_exec('mysqldump --host='.$CONFIG['dbhost'].
|
|
|
+ ' --user='.(empty($SQL_DUMP_USER)?$CONFIG['dbuser']:$SQL_DUMP_USER).
|
|
|
+ ' --password='.escapeshellcmd( empty($SQL_DUMP_PASS)?$CONFIG['dbpassword']:$SQL_DUMP_PASS ).' '.$CONFIG['dbname'].
|
|
|
+ ' > '.$PATH_BACKUP . DIRECTORY_SEPARATOR . 'backup.sql');
|
|
|
+if (strpos(' '.strtolower($process), 'error:') > 0) {
|
|
|
+ echo "sql dump error\n";
|
|
|
+ die;
|
|
|
+} else {
|
|
|
+ echo "\n(to restore: mysql -u ".(empty($SQL_DUMP_USER)?$CONFIG['dbuser']:$SQL_DUMP_USER)." -p ".$CONFIG['dbname']." < backup.sql)\n";
|
|
|
+}
|
|
|
+
|
|
|
+echo "\nbackup config.php...";
|
|
|
+$copy = 1;
|
|
|
+if(file_exists($PATH_BACKUP.'/config.php')){
|
|
|
+ if (filemtime($PATH_NEXTCLOUD.'/config/config.php') > filemtime($PATH_BACKUP.'/config.php') ) {
|
|
|
+ unlink($PATH_BACKUP.'/config.php');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ echo 'not needed';
|
|
|
+ $copy = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+if ($copy) {
|
|
|
+ copy($PATH_NEXTCLOUD.'/config/config.php', $PATH_BACKUP.'/config.php');
|
|
|
+}
|
|
|
+
|
|
|
+echo "\nconnect to S3...";
|
|
|
+$bucket = $CONFIG['objectstore']['arguments']['bucket'];
|
|
|
+$s3 = new S3Client([
|
|
|
+ 'version' => 'latest',
|
|
|
+ //'endpoint' => 'https://'.$bucket.'.'.$CONFIG['objectstore']['arguments']['hostname'],
|
|
|
+ 'endpoint' => 'http://'.$CONFIG['objectstore']['arguments']['hostname'],
|
|
|
+ //'bucket' => $bucket,
|
|
|
+ //'bucket_endpoint' => true,
|
|
|
+ 'region' => $CONFIG['objectstore']['arguments']['region'],
|
|
|
+ 'credentials' => [
|
|
|
+ 'key' => $CONFIG['objectstore']['arguments']['key'],
|
|
|
+ 'secret' => $CONFIG['objectstore']['arguments']['secret'],
|
|
|
+ ],
|
|
|
+ 'use_path_style_endpoint' => $CONFIG['objectstore']['arguments']['use_path_style']
|
|
|
+]);
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\nSetting everything up finished ##########################################################";
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\nappdata preview size...";
|
|
|
+$PREVIEW_MAX_AGEU = 0;
|
|
|
+$PREVIEW_1YR_AGEU = 0;
|
|
|
+if ($PREVIEW_MAX_AGE > 0) {
|
|
|
+ echo "\nremove older then ".$PREVIEW_MAX_AGE." day".($PREVIEW_MAX_AGE>1?'s':'');
|
|
|
+
|
|
|
+ $PREVIEW_MAX_AGEU = new DateTime(); // For today/now, don't pass an arg.
|
|
|
+ $PREVIEW_MAX_AGEU->modify("-".$PREVIEW_MAX_AGE." day".($PREVIEW_MAX_AGE>1?'s':''));
|
|
|
+ echo " > clear before ".$PREVIEW_MAX_AGEU->format( 'd-m-Y' )." (U:".$PREVIEW_MAX_AGEU->format( 'U' ).")";
|
|
|
+ $PREVIEW_MAX_AGEU = $PREVIEW_MAX_AGEU->format( 'U' );
|
|
|
+
|
|
|
+} else {
|
|
|
+ echo " (\$PREVIEW_MAX_AGE = 0 days, stats only)";
|
|
|
+}
|
|
|
+$PREVIEW_1YR_AGEU = new DateTime(); // For today/now, don't pass an arg.
|
|
|
+$PREVIEW_1YR_AGEU->modify("-1year");
|
|
|
+$PREVIEW_1YR_AGEU = $PREVIEW_1YR_AGEU->format( 'U' );
|
|
|
+
|
|
|
+$PREVIEW_NOW = [0,0];
|
|
|
+$PREVIEW_DEL = [0,0];
|
|
|
+$PREVIEW_REM = [0,0];
|
|
|
+$PREVIEW_1YR = [0,0];
|
|
|
+
|
|
|
+if (!$result = $mysqli->query("SELECT `ST`.`id`, `FC`.`fileid`, `FC`.`path`, `FC`.`size`, `FC`.`storage_mtime` FROM".
|
|
|
+ " `oc_filecache` as `FC`,".
|
|
|
+ " `oc_storages` as `ST`,".
|
|
|
+ " `oc_mimetypes` as `MT`".
|
|
|
+ " WHERE 1".
|
|
|
+ " AND `FC`.`path` LIKE 'appdata_%'".
|
|
|
+ " AND `FC`.`path` LIKE '%/preview/%'".
|
|
|
+# " AND `ST`.`id` LIKE 'object::%'".
|
|
|
+# " AND `FC`.`fileid` = '".substr($object['Key'],8)."'". # should be only one..
|
|
|
+
|
|
|
+ " AND `ST`.`numeric_id` = `FC`.`storage`".
|
|
|
+ " AND `FC`.`mimetype` = `MT`.`id`".
|
|
|
+ " AND `MT`.`mimetype` != 'httpd/unix-directory'".
|
|
|
+ " ORDER BY `FC`.`storage_mtime` ASC")) {
|
|
|
+ echo "\nERROR: query pos 1";
|
|
|
+ die;
|
|
|
+} else {
|
|
|
+ if ($PREVIEW_MAX_DEL > 0
|
|
|
+ && $PREVIEW_MAX_DEL < 1) {
|
|
|
+ $PREVIEW_MAX_DEL*= $result->num_rows;
|
|
|
+ }
|
|
|
+ while ($row = $result->fetch_assoc()) {
|
|
|
+ // Determine correct path
|
|
|
+ if (substr($row['id'], 0, 13) == 'object::user:') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 13) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ else if (substr($row['id'], 0, 6) == 'home::') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 6) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ } else {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ $user = substr($path, strlen($PATH_DATA. DIRECTORY_SEPARATOR));
|
|
|
+ $user = substr($user,0,strpos($user,DIRECTORY_SEPARATOR));
|
|
|
+
|
|
|
+ if ($PREVIEW_MAX_AGEU > $row['storage_mtime']
|
|
|
+ && $PREVIEW_MAX_DEL > 1) {
|
|
|
+ $PREVIEW_MAX_DEL--;
|
|
|
+ if (empty($TEST)) {
|
|
|
+ if(file_exists($path) && is_file($path)){
|
|
|
+ unlink($path);
|
|
|
+ }
|
|
|
+ $result_s3 = S3del($s3, $bucket, 'urn:oid:'.$row['fileid']);
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$row['fileid']);
|
|
|
+ } else {
|
|
|
+ echo "\nfileID ".$matches[2]." has a preview older then the set \$PREVIEW_MAX_AGE";
|
|
|
+ }
|
|
|
+ $PREVIEW_DEL[1] += $row['size'];
|
|
|
+ $PREVIEW_DEL[0]++;
|
|
|
+ } else {
|
|
|
+ if (preg_match('/\/preview\/([a-f0-9]\/[a-f0-9]\/[a-f0-9]\/[a-f0-9]\/[a-f0-9]\/[a-f0-9]\/[a-f0-9]\/)?([0-9]+)\/[^\/]+$/',$path,$matches)) {
|
|
|
+ #echo "check fileID".$matches[2].' ';
|
|
|
+ $result2 = $mysqli->query("SELECT `storage` FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$matches[2]);
|
|
|
+ if ($result2->num_rows == 0 ) {
|
|
|
+ if (empty($TEST)) {
|
|
|
+ if(file_exists($path) && is_file($path)){
|
|
|
+ unlink($path);
|
|
|
+ }
|
|
|
+ $result_s3 = S3del($s3, $bucket, 'urn:oid:'.$row['fileid']);
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$row['fileid']);
|
|
|
+ } else {
|
|
|
+ echo "\nfileID ".$matches[2]." has a preview, but the source file does not exist, would delete the preview (fileID ".$row['fileid'].")";
|
|
|
+ }
|
|
|
+ $PREVIEW_REM[0]++;
|
|
|
+ $PREVIEW_REM[1] += $row['size'];
|
|
|
+ } else {
|
|
|
+ if ($PREVIEW_1YR_AGEU > $row['storage_mtime'] ) {
|
|
|
+ $PREVIEW_1YR[1] += $row['size'];
|
|
|
+ $PREVIEW_1YR[0]++;
|
|
|
+ }
|
|
|
+ $PREVIEW_NOW[1] += $row['size'];
|
|
|
+ $PREVIEW_NOW[0]++;
|
|
|
+ }
|
|
|
+ $result2->free_result();
|
|
|
+ } else {
|
|
|
+ echo "\n\nERROR: path format not as expected (".$row['fileid']." : $path)";
|
|
|
+ echo "\n\tremove the database entry..";
|
|
|
+ if (empty($TEST)) {
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$row['fileid']);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ echo " ONLY with \$TEST = 0 the DB entry will be removed!";
|
|
|
+ }
|
|
|
+ echo "\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ $result->free_result();
|
|
|
+}
|
|
|
+
|
|
|
+if ($PREVIEW_DEL[0] > 0
|
|
|
+ || $PREVIEW_REM[0] > 0) {
|
|
|
+ echo "\nappdata preview size before :".sprintf('% 8.2f',($PREVIEW_NOW[1]+$PREVIEW_DEL[1])/1024/1024)." Mb\t(".($PREVIEW_NOW[0]+$PREVIEW_DEL[0])." files)";
|
|
|
+ echo "\nappdata preview > 1 year old:".sprintf('% 8.2f',($PREVIEW_1YR[1])/1024/1024)." Mb\t(".$PREVIEW_1YR[0]." files)";
|
|
|
+ echo "\nappdata preview size cleared:".sprintf('% 8.2f',($PREVIEW_DEL[1])/1024/1024)." Mb\t(".$PREVIEW_DEL[0]." files".($PREVIEW_MAX_DEL<1?' MAX DEL ':'').")";
|
|
|
+ echo "\nappdata preview size cleared:".sprintf('% 8.2f',($PREVIEW_DEL[1])/1024/1024)." Mb\t(".$PREVIEW_DEL[0]." files".($PREVIEW_MAX_DEL<1?' MAX DEL ':'').")";
|
|
|
+ echo "\nappdata preview size now :".sprintf('% 8.2f',($PREVIEW_NOW[1])/1024/1024)." Mb\t(".$PREVIEW_NOW[0]." files";
|
|
|
+ if ($PREVIEW_NOW[1]+$PREVIEW_DEL[1] > 0 ) {
|
|
|
+ echo "/ -".floor(($PREVIEW_DEL[1]+$PREVIEW_REM[1])/($PREVIEW_NOW[1]+$PREVIEW_DEL[1])+.5)."%";
|
|
|
+ }
|
|
|
+ echo ")";
|
|
|
+ if (!empty($TEST)) {
|
|
|
+ echo "\n\nNOTE: in TEST-mode, no preview-data has been cleared!";
|
|
|
+ }
|
|
|
+} else {
|
|
|
+ echo "\nappdata preview size :".sprintf('% 8.2f',($PREVIEW_NOW[1])/1024/1024)." Mb\t(".$PREVIEW_NOW[0]." files)";
|
|
|
+ echo "\nappdata preview > 1 year old:".sprintf('% 8.2f',($PREVIEW_1YR[1])/1024/1024)." Mb\t(".$PREVIEW_1YR[0]." files)";
|
|
|
+}
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\nread files in S3...";
|
|
|
+$objects = S3list($s3, $bucket);
|
|
|
+
|
|
|
+$objectIDs = array();
|
|
|
+$objectIDsSize = 0;
|
|
|
+$users = array();
|
|
|
+
|
|
|
+if (is_string($objects)) {
|
|
|
+ echo $objects; # error..
|
|
|
+ die;
|
|
|
+}
|
|
|
+else {
|
|
|
+ echo "\nObjects to process in S3: ".count($objects).' ';
|
|
|
+ $S3_removed = [0,0];
|
|
|
+ $S3_updated = [0,0];
|
|
|
+ $S3_skipped = [0,0];
|
|
|
+
|
|
|
+ // Init progress
|
|
|
+ $complete = count($objects);
|
|
|
+ $prev = '';
|
|
|
+ $current = 0;
|
|
|
+
|
|
|
+ $showinfo = !empty($TEST);
|
|
|
+ $showinfo = $SHOWINFO ? $showinfo : 0;
|
|
|
+
|
|
|
+ foreach ($objects as $object) {
|
|
|
+ $current++;
|
|
|
+ $infoLine = "\n".$current." / ".substr($object['Key'],8)."\t".$object['Key'] . "\t" . $object['Size'] . "\t" . $object['LastModified'] . "\t";
|
|
|
+
|
|
|
+ if (!$result = $mysqli->query("SELECT `ST`.`id`, `FC`.`fileid`, `FC`.`path`, `FC`.`storage_mtime`, `FC`.`size` FROM".
|
|
|
+ " `oc_filecache` AS `FC`,".
|
|
|
+ " `oc_storages` AS `ST`,".
|
|
|
+ " `oc_mimetypes` AS `MT`".
|
|
|
+ " WHERE 1".
|
|
|
+ # " AND st.id LIKE 'object::%'".
|
|
|
+ " AND `FC`.`fileid` = '".substr($object['Key'],8)."'". # should be only one..
|
|
|
+
|
|
|
+ " AND `ST`.`numeric_id` = `FC`.`storage`".
|
|
|
+ " AND `FC`.`mimetype` = `MT`.`id`".
|
|
|
+ " AND `MT`.`mimetype` != 'httpd/unix-directory'".
|
|
|
+ " ORDER BY `FC`.`path` ASC")) {#
|
|
|
+ echo "\nERROR: query pos 2";
|
|
|
+ die;
|
|
|
+ } else {
|
|
|
+ if ($result->num_rows>1) {
|
|
|
+ echo "\ndouble file found in oc_filecache, this can not be!?\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+ else if ($result->num_rows == 0) { # in s3, not in db, remove from s3
|
|
|
+ if ($showinfo) { echo $infoLine."\nID:".$object['Key']."\ton S3, but not in oc_filecache, remove..."; }
|
|
|
+ if (!empty($TEST) && $TEST == 2) {
|
|
|
+ echo ' not removed ($TEST = 2)';
|
|
|
+ } else {
|
|
|
+ $result_s3 = S3del($s3, $bucket, $object['Key']);
|
|
|
+ if ($showinfo) { echo 'S3del:'.$result_s3; }
|
|
|
+ }
|
|
|
+ $S3_removed[0]++;
|
|
|
+ $S3_removed[1]+=$object['Size'];
|
|
|
+ }
|
|
|
+ else { # one match, up to date?
|
|
|
+ $row = $result->fetch_assoc();
|
|
|
+
|
|
|
+ // Determine correct path
|
|
|
+ if (substr($row['id'], 0, 13) == 'object::user:') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 13) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ else if (substr($row['id'], 0, 6) == 'home::') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 6) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ } else {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ $user = substr($path, strlen($PATH_DATA. DIRECTORY_SEPARATOR));
|
|
|
+ $user = substr($user,0,strpos($user,DIRECTORY_SEPARATOR));
|
|
|
+ $users[ $user ] = 1;
|
|
|
+
|
|
|
+ $infoLine.= $user. "\t";
|
|
|
+
|
|
|
+ # just for one user? set test = appdata_oczvcie795w3 (system wil not go to maintenance nor change database, just test and copy data!!)
|
|
|
+ if (is_numeric($TEST) || $TEST == $user ) {
|
|
|
+ #echo "\n".$path."\t".$row['storage_mtime'];
|
|
|
+ if(file_exists($path) && is_file($path)){
|
|
|
+ if ($row['storage_mtime'] < filemtime($path) ) {
|
|
|
+ if ($showinfo) { echo $infoLine."\nID:".$object['Key']."\ton S3, but is older then local, upload..."; }
|
|
|
+ if (!empty($TEST) && $TEST == 2) {
|
|
|
+ echo ' not uploaded ($TEST = 2)';
|
|
|
+ } else {
|
|
|
+ $result_s3 = S3put($s3, $bucket,[
|
|
|
+ 'Key' => 'urn:oid:'.$row['fileid'],
|
|
|
+ #'Body'=> "Hello World!!",
|
|
|
+ 'SourceFile' => $path,
|
|
|
+ 'ACL' => 'private'//public-read'
|
|
|
+ ]);
|
|
|
+ if ($showinfo) { echo 'S3put:'.$result_s3; }
|
|
|
+ }
|
|
|
+ $S3_updated[0]++;
|
|
|
+ $S3_updated[1]+=$row['size'];
|
|
|
+ } else {
|
|
|
+ $objectIDs[ $row['fileid'] ] = 1;
|
|
|
+ $objectIDsSize+=$row['size'];
|
|
|
+# if ($showinfo) { echo $infoLine."OK (".$row['fileid']." / ".(count($objectIDs)).")"; }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $objectIDs[ $row['fileid'] ] = 1;
|
|
|
+ $objectIDsSize+=$row['size'];
|
|
|
+# if ($showinfo) { echo $infoLine."OK-S3 (".$row['fileid']." / ".(count($objectIDs)).")"; }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $S3_skipped[0]++;
|
|
|
+ $S3_skipped[1]+=$row['size'];
|
|
|
+# if ($showinfo) { echo "SKIP (TEST=$TEST)"; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Update progress
|
|
|
+ $new = sprintf('%.2f',$current/$complete*100).'% (now at user '.$user.')';
|
|
|
+ if ($prev != $new && !$showinfo) {
|
|
|
+ echo str_repeat(chr(8) , strlen($prev) );
|
|
|
+ $new.= (strlen($prev)<=strlen($new))? '' : str_repeat(' ' , strlen($prev)-strlen($new) );
|
|
|
+ $prev = $new;
|
|
|
+ echo $prev;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $result->free_result();
|
|
|
+ }
|
|
|
+ if (!$showinfo) {
|
|
|
+ echo str_repeat(chr(8) , strlen($prev) );
|
|
|
+ $new = ' DONE ';
|
|
|
+ $new.= (strlen($prev)<=strlen($new))? '' : str_repeat(' ' , strlen($prev)-strlen($new) );
|
|
|
+ $prev = $new;
|
|
|
+ echo $prev;
|
|
|
+ }
|
|
|
+ if ($showinfo) { echo "\nNumber of objects in S3: ".count($objects); }
|
|
|
+ echo "\nobjects removed from S3: ".$S3_removed[0] ."\t(".readableBytes($S3_removed[1]).")";
|
|
|
+ echo "\nobjects updated to S3: ".$S3_updated[0] ."\t(".readableBytes($S3_updated[1]).")";
|
|
|
+ echo "\nobjects skipped on S3: ".$S3_skipped[0] ."\t(".readableBytes($S3_skipped[1]).")";
|
|
|
+ echo "\nobjects in sync on S3: ".count($objectIDs)."\t(".readableBytes($objectIDsSize).")";
|
|
|
+ if ($S3_removed[0]+$S3_updated[0]+$S3_skipped[0]+count($objectIDs) - count($objects) != 0 ) {
|
|
|
+ echo "\n\nERROR: The numbers do not add up!?\n\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+echo "\n".
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\ncheck files in oc_filecache... ";
|
|
|
+
|
|
|
+if (!$result = $mysqli->query("SELECT `ST`.`id`, `FC`.`fileid`, `FC`.`path`, `FC`.`storage_mtime`, `FC`.`size` FROM".
|
|
|
+ " `oc_filecache` AS `FC`,".
|
|
|
+ " `oc_storages` AS `ST`,".
|
|
|
+ " `oc_mimetypes` AS `MT`".
|
|
|
+ " WHERE 1".
|
|
|
+# " AND fc.size != 0".
|
|
|
+# " AND st.id LIKE 'object::%'".
|
|
|
+# " AND fc.fileid = '".substr($object['Key'],8)."'". # should be only one..
|
|
|
+
|
|
|
+ " AND `ST`.`numeric_id` = `FC`.`storage`".
|
|
|
+ " AND `FC`.`mimetype` = `MT`.`id`".
|
|
|
+ " AND `MT`.`mimetype` != 'httpd/unix-directory'".
|
|
|
+ " ORDER BY `ST`.`id`, `FC`.`fileid` ASC")) {
|
|
|
+ echo "\nERROR: query pos 3\n\n";
|
|
|
+ die;
|
|
|
+} else {
|
|
|
+ // Init progress
|
|
|
+ $complete = $result->num_rows;
|
|
|
+ $prev = '';
|
|
|
+ $current = 0;
|
|
|
+
|
|
|
+ echo "\nNumber of objects in oc_filecache: ".$result->num_rows.' ';
|
|
|
+
|
|
|
+ $showinfo = !empty($TEST);
|
|
|
+ $showinfo = 0;
|
|
|
+
|
|
|
+ $LOCAL_ADDED = [0,0];
|
|
|
+ while ($row = $result->fetch_assoc()) {
|
|
|
+ $current++;
|
|
|
+
|
|
|
+ if (empty($objectIDs[ $row['fileid'] ]) ) {
|
|
|
+ // Determine correct path
|
|
|
+ if (substr($row['id'], 0, 13) == 'object::user:') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 13) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ else if (substr($row['id'], 0, 6) == 'home::') {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . substr($row['id'], 6) . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ } else {
|
|
|
+ $path = $PATH_DATA . DIRECTORY_SEPARATOR . $row['path'];
|
|
|
+ }
|
|
|
+ $user = substr($path, strlen($PATH_DATA. DIRECTORY_SEPARATOR));
|
|
|
+ $user = substr($user,0,strpos($user,DIRECTORY_SEPARATOR));
|
|
|
+ $users[ $user ] = 1;
|
|
|
+
|
|
|
+ if ($showinfo) { echo "\n".$user."\t".$row['fileid']."\t".$path."\t"; }
|
|
|
+
|
|
|
+ # just for one user? set test = appdata_oczvcie795w3 (system wil not go to maintenance nor change database, just test and copy data!!)
|
|
|
+ if (is_numeric($TEST) || $TEST == $user ) {
|
|
|
+ if(file_exists($path) && is_file($path)){
|
|
|
+ if (!empty($TEST) && $TEST == 2) {
|
|
|
+ echo ' not uploaded ($TEST = 2)';
|
|
|
+ } else {
|
|
|
+ $result_s3 = S3put($s3, $bucket,[
|
|
|
+ 'Key' => 'urn:oid:'.$row['fileid'],
|
|
|
+ #'Body'=> "Hello World!!",
|
|
|
+ 'SourceFile' => $path,
|
|
|
+ 'ACL' => 'private'//public-read'
|
|
|
+ ]);
|
|
|
+ if (strpos(' '.$result_s3,'ERROR:') == 1) {
|
|
|
+ echo "\n".$result_s3."\n\n";
|
|
|
+ die;
|
|
|
+ }
|
|
|
+ if ($showinfo) { echo "OK"; }
|
|
|
+ }
|
|
|
+ $LOCAL_ADDED[0]++;
|
|
|
+ $LOCAL_ADDED[1]+=$row['size'];
|
|
|
+ } else {
|
|
|
+ echo "\n".$path." (id:".$row['fileid'].") DOES NOT EXIST?!\n";
|
|
|
+ if (empty($TEST)) {
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$row['fileid']);
|
|
|
+ echo "\t".'removed ($TEST = 0)'."\n";
|
|
|
+ } else {
|
|
|
+ echo "\t".'not removed ($TEST != 0)'."\n";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if ($showinfo) {
|
|
|
+ echo "SKIP (\$TEST = $TEST)";
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ($showinfo) { echo "\n"."\t".$row['fileid']."\t".$row['path']."\t"."SKIP";}
|
|
|
+ }
|
|
|
+ // Update progress
|
|
|
+ $new = sprintf('%.2f',$current/$complete*100).'% (now at user '.$user.')';
|
|
|
+
|
|
|
+ if ($prev != $new && !$showinfo) {
|
|
|
+ echo str_repeat(chr(8) , strlen($prev) );
|
|
|
+ $new.= (strlen($prev)<=strlen($new))? '' : str_repeat(' ' , strlen($prev)-strlen($new) );
|
|
|
+ $prev = $new;
|
|
|
+ echo $prev;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $result->free_result();
|
|
|
+ if (!$showinfo) {
|
|
|
+ echo str_repeat(chr(8) , strlen($prev) );
|
|
|
+ $new = ' DONE ';
|
|
|
+ $new.= (strlen($prev)<=strlen($new))? '' : str_repeat(' ' , strlen($prev)-strlen($new) );
|
|
|
+ $prev = $new;
|
|
|
+ echo $prev;
|
|
|
+ }
|
|
|
+ echo "\nFiles in oc_filecache added to S3: ".$LOCAL_ADDED[0]."\t(".readableBytes($LOCAL_ADDED[1]).")";
|
|
|
+}
|
|
|
+echo "\nCopying files finished";
|
|
|
+
|
|
|
+echo "\n". # inspiration source: https://github.com/otherguy/nextcloud-cleanup/blob/main/clean.php
|
|
|
+ "\n#########################################################################################".
|
|
|
+ "\ncheck for canceled uploads in oc_filecache...".
|
|
|
+ "\n=> EXPERIMENTAL, I have not had this problem, so can not test.. => check only!";
|
|
|
+
|
|
|
+if (!$result = $mysqli->query("SELECT `oc_filecache`.`fileid`, `oc_filecache`.`path`, `oc_filecache`.`parent`, `oc_storages`.`id` AS `storage`, `oc_filecache`.`size`".
|
|
|
+ " FROM `oc_filecache`".
|
|
|
+ " LEFT JOIN `oc_storages` ON `oc_storages`.`numeric_id` = `oc_filecache`.`storage`".
|
|
|
+ " WHERE `oc_filecache`.`parent` IN (".
|
|
|
+ " SELECT `fileid`".
|
|
|
+ " FROM `oc_filecache`".
|
|
|
+ " WHERE `parent` IN (SELECT fileid FROM `oc_filecache` WHERE `path`='uploads')".
|
|
|
+ " AND `storage_mtime` < UNIX_TIMESTAMP(NOW() - 24 * 60 * 60)".
|
|
|
+ " ) AND `oc_storages`.`available` = 1")) {
|
|
|
+ echo "\nERROR: query pos 4";
|
|
|
+ die;
|
|
|
+} else {
|
|
|
+ $S3_removed = [0,0];
|
|
|
+ $S3_PARENTS = [];
|
|
|
+
|
|
|
+ while ($row = $result->fetch_assoc()) {
|
|
|
+ echo "\nCanceled upload: ".$row['path']." ( ".$row['size']." bytes)";
|
|
|
+ $S3_removed[0]++;
|
|
|
+ $S3_removed[1]+=$row['size'];
|
|
|
+ // Add parent object to array
|
|
|
+ $S3_PARENTS[] = $row['parent'];
|
|
|
+ if ( 1 ) {
|
|
|
+ echo ' EXPERIMENTAL: no deletion, only detection';
|
|
|
+ } else
|
|
|
+ if (!empty($TEST) && $TEST == 2) {
|
|
|
+ echo ' not removed ($TEST = 2)';
|
|
|
+ } else {
|
|
|
+ $result_s3 = S3del($s3, $bucket, 'urn:oid:'.$row['fileid']);
|
|
|
+ if ($showinfo) { echo 'S3del:'.$result_s3; }
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$row['fileid']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($S3_removed[0] > 0 ) {
|
|
|
+ echo "\nobjects removed from S3: ".$S3_removed[0]."\t(".readableBytes($S3_removed[1]).")";
|
|
|
+ // Delete all parent objects from the db
|
|
|
+ $S3_PARENTS = array_unique($S3_PARENTS);
|
|
|
+ echo "\nremoving parents... (".count($S3_PARENTS)." database entries)";
|
|
|
+ foreach ($S3_PARENTS as $s3_parent) {
|
|
|
+ echo "\nparent obeject id: ".$s3_parent;
|
|
|
+ if ( 1 ) {
|
|
|
+ echo ' EXPERIMENTAL: no deletion, only detection';
|
|
|
+ } else
|
|
|
+ if (!empty($TEST) && $TEST == 2) {
|
|
|
+ echo ' not removed ($TEST = 2)';
|
|
|
+ } else {
|
|
|
+ $mysqli->query("DELETE FROM `oc_filecache` WHERE `oc_filecache`.`fileid` = ".$s3_parent);
|
|
|
+ echo ' removed';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#########################################################################################
|
|
|
+if (empty($TEST)) {
|
|
|
+ $dashLine = "\n".
|
|
|
+ "\n#########################################################################################";
|
|
|
+
|
|
|
+ $mysqli->query("UPDATE `oc_storages` SET `id`=CONCAT('object::user:', SUBSTRING_INDEX(`oc_storages`.`id`,':',-1)) WHERE `oc_storages`.`id` LIKE 'home::%'");
|
|
|
+ $UpdatesDone = $mysqli->affected_rows;
|
|
|
+
|
|
|
+ //rename command
|
|
|
+ if ($LOCAL_STORE_ID == 0
|
|
|
+ || $OBJECT_STORE_ID== 0) { // standard rename
|
|
|
+ $mysqli->query("UPDATE `oc_storages` SET `id`='object::store:amazon::".$bucket."' WHERE `oc_storages`.`id` LIKE 'local::".$PATH_DATA."/'");
|
|
|
+ $UpdatesDone.= '/'.$mysqli->affected_rows;
|
|
|
+ } else {
|
|
|
+ $mysqli->query("UPDATE `oc_filecache` SET `storage` = '".$OBJECT_STORE_ID."' WHERE `storage` = '".$LOCAL_STORE_ID."'");
|
|
|
+ $UpdatesDone.= '/'.$mysqli->affected_rows;
|
|
|
+ #$mysqli->query("DELETE FROM `oc_storages` WHERE `oc_storages`.`numeric_id` = ".$OBJECT_STORE_ID);
|
|
|
+ }
|
|
|
+ if ($UpdatesDone == '0/0' ) {
|
|
|
+# echo $dashLine." no modefications needed";
|
|
|
+ } else {
|
|
|
+ echo $dashLine."\noc_storages altered (".$UpdatesDone.")";
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($users as $key => $value) {
|
|
|
+ $mysqli->query("UPDATE `oc_mounts` SET `mount_provider_class` = REPLACE(`mount_provider_class`, 'LocalHomeMountProvider', 'ObjectHomeMountProvider') WHERE `user_id` = '".$key."'");
|
|
|
+ if ($mysqli->affected_rows == 1) {
|
|
|
+ echo $dashLine."\n-Changed mount provider class off ".$key." from home to object";
|
|
|
+ $dashLine = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ echo "\n".
|
|
|
+ "\n#########################################################################################";
|
|
|
+
|
|
|
+ if ($PREVIEW_DEL[1] > 0 ) {
|
|
|
+ echo "\nThere were preview images removed";
|
|
|
+ echo "\nNOTE: you can optionally run occ preview:generate-all => pre generate previews, do install preview generator)\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($users as $key => $value) {
|
|
|
+ if (is_dir($PATH_DATA . DIRECTORY_SEPARATOR . $key)) {
|
|
|
+ echo "\nNOTE: you can remove the user folder of $key\tby: rm -rf ".$PATH_DATA . DIRECTORY_SEPARATOR . $key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ echo "\n";
|
|
|
+
|
|
|
+ if (is_string($CONFIG_OBJECTSTORE) && file_exists($CONFIG_OBJECTSTORE) ) {
|
|
|
+ echo "\nCopy storage.config.php to the config folder...".
|
|
|
+ copy($CONFIG_OBJECTSTORE,$PATH_NEXTCLOUD.'/config/storage.config.php');
|
|
|
+
|
|
|
+ if ($SET_MAINTENANCE) { // maintenance mode
|
|
|
+ $process = occ($OCC_BASE,'maintenance:mode --off');
|
|
|
+ echo $process;
|
|
|
+ }
|
|
|
+ echo "\n#########################################################################################".
|
|
|
+ "\n".
|
|
|
+ "\nALL DONE!".
|
|
|
+ "\n".
|
|
|
+ "\nLog into your Nextcloud instance and check!".
|
|
|
+ "\n".
|
|
|
+ "\nIf all looks well: do not forget to remove '/config/storage.config.php' (it should be".
|
|
|
+ "\n included in your config: having double config data is a risk..)".
|
|
|
+ "\nIf it's not OK : set your instance in 'maintenance:mode --on' & restore your SQL backup".
|
|
|
+ "\n you'll be back to 'local' (let me know, via GitHub, I'll try to help)".
|
|
|
+ "\n#########################################################################################";
|
|
|
+ }
|
|
|
+ else if ($OBJECT_STORE_ID > 0 ) {
|
|
|
+ if ($SET_MAINTENANCE) { // maintenance mode
|
|
|
+ $process = occ($OCC_BASE,'maintenance:mode --off');
|
|
|
+ echo $process;
|
|
|
+ }
|
|
|
+ echo "\n#########################################################################################".
|
|
|
+ "\n".
|
|
|
+ "\nALL DONE!".
|
|
|
+ "\n".
|
|
|
+ "\nLog into your Nextcloud instance and check!".
|
|
|
+ "\n".
|
|
|
+ "\n#########################################################################################";
|
|
|
+ } else {
|
|
|
+ echo "\n#########################################################################################".
|
|
|
+ "\n".
|
|
|
+ "\nALMOST done, one more step:".
|
|
|
+ "\n".
|
|
|
+ "\n ====== ! ! THIS MUST BE DONE MANUALY ! ! ======".
|
|
|
+ "\n 1: add \$CONFIG_OBJECTSTORE to your config.php".
|
|
|
+ "\n 2: turn maintenance mode off".
|
|
|
+ "\n".
|
|
|
+ "\nThe importance of the order to do this is EXTREME, other order can brick your Nextcloud!!\n".
|
|
|
+ "\n".
|
|
|
+ "\n#########################################################################################";
|
|
|
+ }
|
|
|
+ echo "\n\n";
|
|
|
+
|
|
|
+} else {
|
|
|
+ echo "\n\ndone testing..\n";
|
|
|
+}
|
|
|
+
|
|
|
+#########################################################################################
|
|
|
+function occ($OCC_BASE,$OCC_COMMAND) {
|
|
|
+ $result = "\nset ".$OCC_COMMAND.":\n";
|
|
|
+
|
|
|
+ ob_start();
|
|
|
+ passthru($OCC_BASE . $OCC_COMMAND);
|
|
|
+ $process = ob_get_contents();
|
|
|
+ ob_end_clean(); //Use this instead of ob_flush()
|
|
|
+
|
|
|
+ return $result.$process."\n";
|
|
|
+}
|
|
|
+
|
|
|
+#########################################################################################
|
|
|
+function S3list($s3, $bucket, $maxIteration = 10000000) {
|
|
|
+ $objects = [];
|
|
|
+ try {
|
|
|
+ $iteration = 0;
|
|
|
+ $marker = '';
|
|
|
+ do {
|
|
|
+ $result = $s3->listObjects(['Bucket' => $bucket, 'Marker' => $marker]);
|
|
|
+
|
|
|
+ if (rand(0,100) > 75 ) { echo '.'; }
|
|
|
+
|
|
|
+ if ($result->get('Contents')) {
|
|
|
+ $objects = array_merge($objects, $result->get('Contents'));
|
|
|
+ }
|
|
|
+ if (count($objects)) {
|
|
|
+ $marker = $objects[count($objects) - 1]['Key'];
|
|
|
+ }
|
|
|
+ } while ($result->get('IsTruncated') && ++$iteration < $maxIteration);
|
|
|
+ if ($result->get('IsTruncated')) {
|
|
|
+ echo "\n".'WARNING: The number of keys greater than '.count($objects).' (the first part is loaded)';
|
|
|
+ }
|
|
|
+ return $objects;
|
|
|
+ } catch (S3Exception $e) {
|
|
|
+ return 'ERROR: Cannot retrieve objects: '.$e->getMessage();
|
|
|
+ }
|
|
|
+}
|
|
|
+#########################################################################################
|
|
|
+function S3put($s3, $bucket, $vars = array() ) {
|
|
|
+ #return 'dummy';
|
|
|
+ if (is_string($vars) ) {
|
|
|
+ if (file_exists($vars)) {
|
|
|
+ $vars = array('SourceFile' => $vars);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 'ERROR: S3put($cms, $bucket, $vars)';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (empty($vars['Bucket']) ) { $vars['Bucket'] = $bucket; }
|
|
|
+ if (empty($vars['Key'])
|
|
|
+ && !empty($vars['SourceFile'])) { $vars['Key'] = $vars['SourceFile']; }
|
|
|
+ if (empty($vars['ACL']) ) { $vars['Key'] = 'private'; }
|
|
|
+
|
|
|
+ if (empty($vars['Bucket']) ) { return 'ERROR: no Bucket'; }
|
|
|
+ if (empty($vars['Key']) ) { return 'ERROR: no Key'; }
|
|
|
+ if (!file_exists($vars['SourceFile'])) { return 'ERROR: file \''.$vars['SourceFile'].'\' does not exist'; }
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (isset($GLOBALS['MULTIPART_THRESHOLD'])
|
|
|
+ && filesize($vars['SourceFile']) > $GLOBALS['MULTIPART_THRESHOLD']*1024*1024) {
|
|
|
+ $uploader = new MultipartUploader($s3,
|
|
|
+ $vars['SourceFile'],
|
|
|
+ $vars);
|
|
|
+ $result = $uploader->upload();
|
|
|
+ } else {
|
|
|
+ if (filesize($vars['SourceFile']) > 2*1024*1024*1024) {
|
|
|
+ echo "\n".'WARNING: file \''.$vars['SourceFile'].'\' is larger then 2 Gb, consider enabeling \'MultipartUploader\'';
|
|
|
+ }
|
|
|
+ $result = $s3->putObject($vars);
|
|
|
+ }
|
|
|
+ if (!empty($result['ObjectURL'])) {
|
|
|
+ return 'OK: '.'ObjectURL:'.$result['ObjectURL'];
|
|
|
+ } else {
|
|
|
+ return 'ERROR: '.$vars['Key'].' was not uploaded';
|
|
|
+ }
|
|
|
+ } catch (MultipartUploadException | S3Exception | Exception $e) {
|
|
|
+ return 'ERROR: ' . $e->getMessage();
|
|
|
+ }
|
|
|
+}
|
|
|
+#########################################################################################
|
|
|
+function S3del($s3, $bucket, $vars = array() ) {
|
|
|
+ #return 'dummy';
|
|
|
+ if (is_string($vars) ) { $vars = array('Key' => $vars); }
|
|
|
+ if (empty($vars['Bucket'])) { $vars['Bucket'] = $bucket; }
|
|
|
+
|
|
|
+ if (empty($vars['Bucket'])) { return 'ERROR: no Bucket'; }
|
|
|
+ if (empty($vars['Key']) ) { return 'ERROR: no Key'; }
|
|
|
+
|
|
|
+ try {
|
|
|
+ $result = $s3->deleteObject($vars);
|
|
|
+ return 'OK: '.$vars['Key'].' was deleted (or didn\'t not exist)';
|
|
|
+ } catch (S3Exception $e) { return 'ERROR: ' . $e->getMessage(); }
|
|
|
+}
|
|
|
+#########################################################################################
|
|
|
+function S3get($s3, $bucket, $vars = array() ) {
|
|
|
+ #return 'dummy';
|
|
|
+ if (is_string($vars) ) {
|
|
|
+ $vars = array('Key' => $vars);
|
|
|
+ }
|
|
|
+ if (empty($vars['Bucket']) ) { $vars['Bucket'] = $bucket; } // Bucket = the bucket
|
|
|
+ if (empty($vars['Key'])
|
|
|
+ && !empty($vars['SaveAs'])) { $vars['Key'] = $vars['SaveAs']; } // Key = the file-id/location in s3
|
|
|
+ if (empty($vars['SaveAs'])
|
|
|
+ && !empty($vars['Key']) ) { $vars['SaveAs'] = $vars['Key']; } // SaveAs = local location+name
|
|
|
+
|
|
|
+ if (empty($vars['Bucket'])) { return 'ERROR: no Bucket'; }
|
|
|
+ if (empty($vars['Key']) ) { return 'ERROR: no Key'; }
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (1 || $cms['aws']['client']->doesObjectExist($vars['Bucket']
|
|
|
+ ,$vars['Key']) ) {
|
|
|
+ return $cms['aws']['client']->getObject($vars);
|
|
|
+ } else {
|
|
|
+ return 'ERROR: '.$vars['Key'].' does not exist';
|
|
|
+ }
|
|
|
+ } catch (S3Exception $e) { return 'ERROR: ' . $e->getMessage(); }
|
|
|
+}
|
|
|
+
|
|
|
+#########################################################################################
|
|
|
+function readableBytes($bytes) {
|
|
|
+ if ($bytes == 0) { return "0 bytes"; }
|
|
|
+ $i = floor(log($bytes) / log(1024));
|
|
|
+ $sizes = array('bytes', 'kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb');
|
|
|
+ return sprintf('% 5.2f', $bytes / pow(1024, $i)) * 1 . ' ' . $sizes[$i];
|
|
|
+ #return sprintf('%.02F', $bytes / pow(1024, $i)) * 1 . ' ' . $sizes[$i];
|
|
|
+}
|