'error', 'message' => 'Authentication failed']); die(); } if ($_POST['action'] == 'icc_upload_chunk') { icc_upload_and_shorten_handle_chunk(); } if ($_POST['action'] == 'icc_upload_finish') { icc_upload_and_shorten_handle_finish(); } } } function icc_upload_and_shorten_handle_chunk() { $nonce = $_POST['nonce'] ?? ''; if (!yourls_verify_nonce('icc_upload_chunk', $nonce)) { echo json_encode(['status' => 'error', 'message' => 'Security check failed']); die(); } if (!isset($_FILES['file_chunk']) || $_FILES['file_chunk']['error'] != UPLOAD_ERR_OK) { echo json_encode(['status' => 'error', 'message' => 'Upload error']); die(); } $upload_id = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['upload_id']); $temp_dir = yourls_get_option('icc_upload_share_dir'); if (!$temp_dir) $temp_dir = sys_get_temp_dir(); // Create a temp directory for this upload $target_dir = rtrim($temp_dir, '/') . '/icc_temp_' . $upload_id; if (!is_dir($target_dir)) mkdir($target_dir, 0755, true); $chunk_index = intval($_POST['chunk_index']); $target_file = $target_dir . '/part_' . $chunk_index; if (move_uploaded_file($_FILES['file_chunk']['tmp_name'], $target_file)) { echo json_encode(['status' => 'success']); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to move chunk']); } die(); } function icc_upload_and_shorten_handle_finish() { $nonce = $_POST['nonce'] ?? ''; if (!yourls_verify_nonce('icc_upload_chunk', $nonce)) { echo json_encode(['status' => 'error', 'message' => 'Security check failed']); die(); } $upload_id = preg_replace('/[^a-zA-Z0-9_]/', '', $_POST['upload_id']); $file_name = $_POST['file_name']; $temp_dir = yourls_get_option('icc_upload_share_dir'); if (!$temp_dir) $temp_dir = sys_get_temp_dir(); $target_dir = rtrim($temp_dir, '/') . '/icc_temp_' . $upload_id; $final_file_path = $target_dir . '/' . $file_name; // Assemble chunks if ($fp = fopen($final_file_path, 'wb')) { $chunks = glob($target_dir . '/part_*'); natsort($chunks); foreach ($chunks as $chunk) { $chunk_content = file_get_contents($chunk); fwrite($fp, $chunk_content); unlink($chunk); } fclose($fp); rmdir($target_dir); // Remove temp dir // now process the file // Pass essential POST data for filename conversion if needed $result = icc_upload_and_shorten_process_upload($final_file_path, $file_name); // Since the result is HTML string, we might want to return it or parse it // But for this AJAX response we return it in message echo json_encode(['status' => 'success', 'message' => $result]); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to assemble file']); } die(); } // Display admin page function icc_upload_and_shorten_do_page() { // Check if a form was submitted if (isset($_POST['action']) && $_POST['action'] == 'icc_upload_and_shorten_save') { icc_upload_and_shorten_update_settings(); } // Handle Deletion if (isset($_POST['action']) && $_POST['action'] == 'delete_local_file' && isset($_POST['file_name'])) { $nonce = $_POST['nonce'] ?? ''; if (yourls_verify_nonce('icc_delete_local_file', $nonce)) { $share_dir = yourls_get_option('icc_upload_share_dir'); $file_name = $_POST['file_name']; // Validating filename to prevent directory traversal if (basename($file_name) == $file_name) { $file_path = rtrim($share_dir, '/') . '/' . $file_name; if (file_exists($file_path)) { if (unlink($file_path)) { echo "
Server Limits: Upload Max Filesize: $max_upload, Post Max Size: $max_post.
The Smart Uploader bypasses these limits by splitting files into chunks!
$message
"; } if ( ($storage_type == 'local' && (empty($share_url) || empty($share_dir))) || ($storage_type == 's3' && (empty($s3_key) || empty($s3_secret) || empty($s3_region) || empty($s3_bucket))) ) { echo 'Please configure the plugin below before using this plugin.
'; } $chunk_nonce = yourls_create_nonce('icc_upload_chunk'); echo ' '; // JS for Chunked Upload echo ' '; // File Manager if ($storage_type == 's3' && !empty($s3_key) && !empty($s3_secret) && !empty($s3_bucket)) { icc_upload_and_shorten_file_manager($s3_key, $s3_secret, $s3_region, $s3_bucket); } elseif ($storage_type == 'local' && !empty($share_dir)) { icc_upload_and_shorten_local_file_manager($share_dir, $share_url); } // Configuration Section $nonce = yourls_create_nonce('icc_upload_and_shorten_settings'); echo 'Directory not found: ' . htmlspecialchars($dir) . '
'; return; } $raw_files = scandir($dir); $files = []; foreach ($raw_files as $f) { if ($f == '.' || $f == '..') continue; $full_path = rtrim($dir, '/') . '/' . $f; // Exclude directories (like the temp ones if they exist) if (!is_dir($full_path)) { $files[] = $f; } } // Sort by modification time (Newest first) usort($files, function ($a, $b) use ($dir) { return filemtime(rtrim($dir, '/') . '/' . $b) - filemtime(rtrim($dir, '/') . '/' . $a); }); // $files = array_values($files); // Already indexed 0..n by sorting // Pagination $per_page = 20; $total_files = count($files); $total_pages = ceil($total_files / $per_page); $current_page = isset($_GET['local_page']) ? max(1, intval($_GET['local_page'])) : 1; $offset = ($current_page - 1) * $per_page; $page_files = array_slice($files, $offset, $per_page); if (empty($page_files)) { echo 'No files found.
'; } else { $nonce = yourls_create_nonce('icc_delete_local_file'); echo '| File Name | Size | Last Modified | Action |
|---|---|---|---|
| ' . htmlspecialchars($file) . ' | '; echo '' . $size . ' | '; echo '' . $date . ' | '; echo ''; echo ''; echo ' | '; echo '
Failed to initialize AWS Client.
'; return; } // Pagination $continuation_token = isset($_GET['s3_next_token']) ? $_GET['s3_next_token'] : null; try { $params = [ 'Bucket' => $bucket, 'MaxKeys' => 20 ]; if ($continuation_token) { $params['ContinuationToken'] = $continuation_token; } $objects = $s3->listObjectsV2($params); if (!isset($objects['Contents']) || empty($objects['Contents'])) { echo 'No files found in bucket.
'; if ($continuation_token) { echo ''; } } else { $nonce = yourls_create_nonce('icc_delete_file'); echo '| File Name | Size | Last Modified | Action |
|---|---|---|---|
| ' . htmlspecialchars($object['Key']) . ' | '; echo '' . round($object['Size'] / 1024, 2) . ' KB | '; echo '' . $object['LastModified'] . ' | '; echo ''; echo ''; echo ' | '; echo '
Showing files from S3 bucket.
'; // Pagination History (to allow 'Previous') $history_raw = isset($_GET['s3_history']) ? $_GET['s3_history'] : ''; $history = $history_raw ? explode(',', $history_raw) : []; // Pagination Controls echo 'Error listing files: ' . $e->getMessage() . '
'; } } // Update option in database function icc_upload_and_shorten_process_upload($local_file_path = null, $original_filename = null) { // If not coming from chunked upload, standard validations if (!$local_file_path) { // did the user select any file? if ($_FILES['file_upload']['error'] == UPLOAD_ERR_NO_FILE) { return 'You need to select a file to upload.'; } } // Increase limits for processing large files set_time_limit(0); $storage_type = yourls_get_option('icc_upload_storage_type', 'local'); // Check Config if ($storage_type == 'local') { $my_url = yourls_get_option('icc_upload_share_url'); $my_uploaddir = yourls_get_option('icc_upload_share_dir'); if (empty($my_url) || empty($my_uploaddir)) return 'Plugin not configured for local storage.'; // Check if directory exists and is writable if (!is_dir($my_uploaddir) || !is_writable($my_uploaddir)) { return 'Upload directory does not exist or is not writable: ' . $my_uploaddir; } } elseif ($storage_type == 's3') { $key = yourls_get_option('icc_upload_s3_key'); $secret = yourls_get_option('icc_upload_s3_secret'); $region = yourls_get_option('icc_upload_s3_region'); $bucket = yourls_get_option('icc_upload_s3_bucket'); $disable_acl = yourls_get_option('icc_upload_s3_disable_acl', false); if (empty($key) || empty($secret) || empty($region) || empty($bucket)) return 'Plugin not configured for S3 storage.'; $s3 = icc_get_aws_client($key, $secret, $region); if (!$s3) return 'AWS SDK not found or failed to initialize, please ensure aws.phar is in the plugin folder.'; } $file_name_to_use = $local_file_path ? $original_filename : $_FILES['file_upload']['name']; // Handle the filename's extension $my_upload_extension = pathinfo($file_name_to_use, PATHINFO_EXTENSION); // If there is any extension at all then append it with a leading dot $my_extension = ''; if (isset($my_upload_extension) && $my_upload_extension != NULL) { $my_extension = '.' . $my_upload_extension; } $my_upload_filename = pathinfo($file_name_to_use, PATHINFO_FILENAME); $my_filename = $my_upload_filename; // Default if (isset($_POST['convert_filename'])) { switch ($_POST['convert_filename']) { case 'browser-safe': { // make the filename web-safe: $my_filename_trim = trim($my_upload_filename); $my_filename_trim = strtolower($my_filename_trim); // Force lowercase $my_extension = strtolower($my_extension); $my_RemoveChars = array("([^()_\-\.,0-9a-zA-Z\[\]])"); // replace what's NOT in here! $my_filename = preg_replace($my_RemoveChars, "_", $my_filename_trim); $my_filename = preg_replace("(_{2,})", "_", $my_filename); $my_extension = preg_replace($my_RemoveChars, "_", $my_extension); $my_extension = preg_replace("(_{2,})", "_", $my_extension); } break; case 'safe_suffix': { // browser-safe + random suffix $my_filename_trim = trim($my_upload_filename); $my_filename_trim = strtolower($my_filename_trim); // Force lowercase $my_extension = strtolower($my_extension); $my_RemoveChars = array("([^()_\-\.,0-9a-zA-Z\[\]])"); $my_filename = preg_replace($my_RemoveChars, "_", $my_filename_trim); $my_filename = preg_replace("(_{2,})", "_", $my_filename); $my_extension = preg_replace($my_RemoveChars, "_", $my_extension); $my_extension = preg_replace("(_{2,})", "_", $my_extension); $suffix_length = yourls_get_option('icc_upload_suffix_length', 4); $suffix = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, $suffix_length); $my_filename .= '_' . $suffix; } break; case 'randomized': { // make up a random name for the uploaded file $my_filename = substr(md5($my_upload_filename . strtotime("now")), 0, 12); } break; } } // avoid duplicate filenames if ($storage_type == 'local') { $my_count = 2; $my_path = $my_uploaddir . $my_filename . $my_extension; $my_final_file_name = $my_filename . $my_extension; while (file_exists($my_path)) { $my_path = $my_uploaddir . $my_filename . '.' . $my_count . $my_extension; $my_final_file_name = $my_filename . '.' . $my_count . $my_extension; $my_count++; } } else { // For S3, exact duplicate check is hard without API call, so we assume timestamp or suffix makes it unique enough // Or we can just overwrite as S3 versioning might be on, but user asked for simple upload // We will just use the name derived. $my_final_file_name = $my_filename . $my_extension; // If we are processing a chunked upload, source is the assembled file // If it's a standard upload, it's the temp file $my_path = $local_file_path ? $local_file_path : $_FILES['file_upload']['tmp_name']; } $my_upload_fullname = pathinfo($file_name_to_use, PATHINFO_BASENAME); // Upload Logic $upload_success = false; if ($storage_type == 'local') { // If local file path provided (Chunked), rename it to destination if ($local_file_path) { if (rename($local_file_path, $my_path)) { $upload_success = true; $final_url = $my_url . $my_final_file_name; } } else { if (move_uploaded_file($_FILES['file_upload']['tmp_name'], $my_path)) { $upload_success = true; $final_url = $my_url . $my_final_file_name; } } } elseif ($storage_type == 's3') { try { $args = [ 'Bucket' => $bucket, 'Key' => $my_final_file_name, 'SourceFile' => $my_path, ]; if (!$disable_acl) { $args['ACL'] = 'public-read'; } $result = $s3->putObject($args); // Cleanup temp file if it was a chunked upload if ($local_file_path && file_exists($local_file_path)) { unlink($local_file_path); } // Use S3 Object URL directly $final_url = $result['ObjectURL']; $upload_success = true; } catch (Aws\S3\Exception\S3Exception $e) { return 'S3 Upload failed: ' . $e->getMessage() . ''; } } if ($upload_success) { // On success: // obey custom shortname, if given: $my_custom_shortname = ''; if (isset($_POST['custom_shortname']) && $_POST['custom_shortname'] != NULL) { $my_custom_shortname = $_POST['custom_shortname']; } // change custom title, if given. Default is original filename, but if user provided one, use it: $my_custom_title = $_POST['convert_filename'] . ': ' . $my_upload_fullname; if (isset($_POST['custom_title']) && $_POST['custom_title'] != NULL) { $my_custom_title = $_POST['custom_title']; } // let YOURLS create the link: $my_short_url = yourls_add_new_link($final_url, $my_custom_shortname, $my_custom_title); return '"' . $my_upload_fullname . '" successfully sent to ' . ($storage_type == 's3' ? 'S3' : 'Server') . '. Links: