diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php new file mode 100644 index 00000000..696cedfb --- /dev/null +++ b/ext/cron_uploader/main.php @@ -0,0 +1,403 @@ + + * Link: http://www.yaoifox.com/ + * License: GPLv2 + * Description: Uploads images automatically using Cron Jobs + * Documentation: + * This cron uploader is fairly easy to use but has to be configured first. + * 1. Install & activate this plugin. + * + * 2. Upload your images you want to be uploaded to the queue directory. (default: shimmie2/data/cron_uploader/queue/) + * You can find the queue Directory Path of your queue in your Board Config. + * This also supports directory names to be used as tags. + * + * 3. Go to the Board Config to the Cron Uploader menu and copy the "Cron Command". + * + * 4. Create a cron job or something else that can open a url on specified times. + * You can find the Cron Command in the Board Config. + * If you're not sure how to do this, you can give the command to your web host and you can ask them to create the cron job for you. + * When you create the cron job, you choose how often to upload a new image. + * + * 5. When the cron command is set up, your image queue will upload x file(s) at the specified times. + * You can see any uploads or failed uploads in the log file. (default: shimmie2/data/cron_uploader/uploads.log) + * Your uploaded images will be moved to the "uploaded" directory, it's recommended that you remove everything out of this directory from time to time. + * (default: shimmie2/data/cron_uploader/uploaded/) + * + * Whenever the url in that cron job command is opened, a new file will upload from the queue. + * So when you want to manually upload an image, all you have to do is open the link once. + * This link can be found under "Cron Command" in the board config, just remove the "wget " part and only the url remains. + */ +class CronUploader extends Extension { + + /** + * Lists all log events this session + * @var string + */ + private $upload_info = ""; + + /** + * Lists all files & info required to upload. + * @var array + */ + private $image_queue = array(); + + /** + * Cron Uploader root directory + * @var string + */ + private $root_dir = ""; + + /** + * Checks if the cron upload page has been accessed + * and initializes the upload. + * @param PageRequestEvent $event + */ + public function onPageRequest(PageRequestEvent $event) { + global $config; + + if ($event->page_matches ( "cron_upload" )) { + $key = $config->get_string ( "cron_uploader_key", "" ); + + if ($key != "" && $event->get_arg ( 0 ) == $key) { + set_time_limit ( 0 ); + + // Set vars + $this->root_dir = $config->get_string("cron_uploader_dir", ""); + + // Process upload & log + $this->process_upload(); // Start upload + $this->handle_log(); // Display & save upload log + } + } + } + + + public function onInitExt(InitExtEvent $event) { + global $config; + // Set default values + $key = $this->generate_key (); + $dir = $this->set_dir (); + $config->set_default_int ( 'cron_uploader_count', 1 ); + $config->set_default_string ( 'cron_uploader_key', $key ); + } + + public function onSetupBuilding(SetupBuildingEvent $event) { + global $config; + $this->root_dir = $config->get_string("cron_uploader_dir", ""); + $cron_url = make_http(make_link("/cron_upload/" . $config->get_string('cron_uploader_key', 'invalid key' ))); + $cron_cmd = "wget $cron_url"; + + $queue_dir = $this->root_dir . "/queue"; + $uploaded_dir = $this->root_dir . "/uploaded"; + $failed_dir = $this->root_dir . "/failed_to_upload"; + + $queue_dirinfo = $this->scan_dir($queue_dir); + $uploaded_dirinfo = $this->scan_dir($uploaded_dir); + $failed_dirinfo = $this->scan_dir($failed_dir); + + $sb = new SetupBlock ( "Cron Uploader" ); + $sb->add_label ( "Settings
" ); + $sb->add_int_option ( "cron_uploader_count", "How many to upload each time" ); + $sb->add_text_option ( "cron_uploader_dir", "
Set Cron Uploader root directory
"); + $sb->add_label ( "

+ Information +
+ + + + + + + + + + + + + + + + + + + + + +
DirectoryFilesSize (MB)Directory Path
Queue{$queue_dirinfo['total_files']}{$queue_dirinfo['total_mb']}
Uploaded{$uploaded_dirinfo['total_files']}{$uploaded_dirinfo['total_mb']}
Failed{$failed_dirinfo['total_files']}{$failed_dirinfo['total_mb']}
+ +
Cron Command:
+ Create a cron job with the command above.
+ Read the documentation if you're not sure what to do.
"); + $event->panel->add_block ( $sb ); + } + + /* + * Generates a unique key for the website to prevent unauthorized access. + */ + private function generate_key() { + $length = 20; + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + + for($i = 0; $i < $length; $i ++) { + $randomString .= $characters [rand ( 0, strlen ( $characters ) - 1 )]; + } + + return $randomString; + } + + /* + * Set the directory for the image queue. If no directory was given, set it to the default directory. + */ + private function set_dir() { + global $config; + // Determine directory (none = default) + $dir = $this->root_dir; + + if ($dir == "") + { + $dir = $_SERVER ['DOCUMENT_ROOT'] . "/data/cron_uploader"; + $config->set_default_string ('cron_uploader_dir', $dir); + } + + // Make the directory if it doesn't exist yet + if (!is_dir($dir . "/queue/")) + mkdir ( $dir . "/queue/", 0755, true ); + if (!is_dir($dir . "/uploaded/")) + mkdir ( $dir . "/uploaded/", 0755, true ); + if (!is_dir($dir . "/failed_to_upload/")) + mkdir ( $dir . "/failed_to_upload/", 0755, true ); + + return $dir; + } + + /** + * Returns amount of files & total size of dir. + * @param unknown $path + * @return multitype:number + */ + function scan_dir($path){ + $ite=new RecursiveDirectoryIterator($path); + + $bytestotal=0; + $nbfiles=0; + foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) { + $filesize = $cur->getSize(); + $bytestotal += $filesize; + $nbfiles++; + } + + $size_mb = $bytestotal / 1048576; // to mb + $size_mb = number_format($size_mb, 2, '.', ''); + return array('total_files'=>$nbfiles,'total_mb'=>$size_mb); + } + + /** + * Uploads the image & handles everything + * @param number $count to upload a non-config amount of imgs + * @return boolean returns true if the upload was successful + */ + public function process_upload($count = 0) { + global $config; + $this->generate_image_queue (); + + // Gets amount of imgs to upload + if ($count == 0) $count = $config->get_int ( "cron_uploader_count", 1 ); + + // Throw exception if there's nothing in the queue + if (count($this->image_queue) == 0) { + $this->add_upload_info("Your queue is empty so nothing could be uploaded."); + return false; + } + + // Randomize Images + shuffle($this->image_queue); + + + // Upload the file(s) + for ($i = 0; $i < $count; $i++) { + $img = $this->image_queue[$i]; + + try { + $this->add_image($img[0], $img[1], $img[2]); + $newPath = $this->move_uploaded($img[0], $img[1], false); + + } + catch (Exception $e) { + $newPath = $this->move_uploaded($img[0], $img[1], true); + } + + // Remove img from queue array + unset($this->image_queue[$i]); + } + + return true; + } + + + private $attempt_count = 0; + private function move_uploaded($path, $filename, $corrupt = false) { + global $config; + + // Create + $newDir = $this->root_dir; + + // Determine which dir to move to + if ($corrupt) { + // Move to corrupt dir + $newDir .= "/failed_to_upload/"; + $info = "ERROR: Image was not uploaded."; + } + else { + $newDir .= "/uploaded/"; + $info = "Image successfully uploaded. "; + } + + // move file to correct dir + $newPath = $newDir . $filename; + rename($path, $newPath); + + $this->add_upload_info($info . "Image \"$filename\" moved from queue to \"$newPath\"."); + } + + + /** + * moves a directory up or gets the directory of a file + * + * @param string $path Path to modify + * @param int $depth Amount of directories to go up + * @return unknown Path to correct Directory + */ + private function move_directory_up($path, $depth=1) + { + $path = str_replace("//", "/", $path); + $array = explode("/", $path); + + for ($i = 0; $i < $depth; $i++) { + $to_remove = count($array) -1; // Gets number of element to remove + unset($array[$to_remove]); + } + + return implode("/", $array); + } + + /** + * Generate the necessary DataUploadEvent for a given image and tags. + */ + private function add_image($tmpname, $filename, $tags) { + assert ( file_exists ( $tmpname ) ); + + $pathinfo = pathinfo ( $filename ); + if (! array_key_exists ( 'extension', $pathinfo )) { + throw new UploadException ( "File has no extension" ); + } + $metadata ['filename'] = $pathinfo ['basename']; + $metadata ['extension'] = $pathinfo ['extension']; + $metadata ['tags'] = $tags; + $metadata ['source'] = null; + $event = new DataUploadEvent ( $tmpname, $metadata ); + send_event ( $event ); + + // Generate info message + $infomsg = ""; // Will contain info message + if ($event->image_id == -1) + $infomsg = "File type not recognised. Filename: {$filename}"; + else $infomsg = "Image uploaded. ID: {$event->image_id} - Filename: {$filename} - Tags: {$tags}"; + $msgNumber = $this->add_upload_info($infomsg); + + } + + private function generate_image_queue($base = "", $subdir = "") { + global $config; + + if ($base == "") + $base = $this->set_dir() . "/queue"; + + if (! is_dir ( $base )) { + $this->add_upload_info("Image Queue Directory could not be found at \"$base\"."); + return array(); + } + + foreach ( glob ( "$base/$subdir/*" ) as $fullpath ) { + $fullpath = str_replace ( "//", "/", $fullpath ); + $shortpath = str_replace ( $base, "", $fullpath ); + + if (is_link ( $fullpath )) { + // ignore + } else if (is_dir ( $fullpath )) { + $this->generate_image_queue ( $base, str_replace ( $base, "", $fullpath ) ); + } else { + $pathinfo = pathinfo ( $fullpath ); + $matches = array (); + + if (preg_match ( "/\d+ - (.*)\.([a-zA-Z]+)/", $pathinfo ["basename"], $matches )) { + $tags = $matches [1]; + } else { + $tags = $subdir; + $tags = str_replace ( "/", " ", $tags ); + $tags = str_replace ( "__", " ", $tags ); + if ($tags == "") $tags = " "; + $tags = trim ( $tags ); + } + + $img = array ( + 0 => $fullpath, + 1 => $pathinfo ["basename"], + 2 => $tags + ); + array_push ($this->image_queue, $img ); + } + } + } + + /** + * Adds a message to the info being published at the end + * @param string $text + * @param int $addon Enter a value to modify an existing value (enter value number) + */ + private function add_upload_info($text, $addon = 0) { + $info = $this->upload_info; + $time = "[" .date('Y-m-d H:i:s'). "]"; + + // If addon function is not used + if ($addon == 0) { + $this->upload_info .= "$time $text\r\n"; + + // Returns the number of the current line + $currentLine = substr_count($this->upload_info, "\n") -1; + return $currentLine; + } + + // else if addon function is used, select the line & modify it + $lines = substr($info, "\n"); // Seperate the string to array in lines + $lines[$addon] = "$line[$addon] $text"; // Add the content to the line + $this->upload_info = implode("\n", $lines); // Put string back together & update + + return $addon; // Return line number + } + + /** + * This is run at the end to display & save the log. + */ + private function handle_log() { + global $page, $config; + + // Display message + $page->set_mode("data"); + $page->set_type("text/plain"); + $page->set_data($this->upload_info); + + // Save log + $log_path = $this->root_dir . "/uploads.log"; + + if (file_exists($log_path)) + $prev_content = file_get_contents($log_path); + else $prev_content = ""; + + $content = $prev_content ."\r\n".$this->upload_info; + file_put_contents ($log_path, $content); + } +} +?> \ No newline at end of file