upload_diagnostic.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /**
  3. * Upload Diagnostic Script
  4. * Helps identify what's limiting file uploads
  5. */
  6. // Start session
  7. if (session_status() === PHP_SESSION_NONE) {
  8. session_start();
  9. }
  10. require_once '../includes/config.php';
  11. require_once '../includes/database.php';
  12. require_once '../includes/auth.php';
  13. // Require authentication
  14. $auth = new Auth();
  15. $auth->requireAuth();
  16. ?>
  17. <!DOCTYPE html>
  18. <html>
  19. <head>
  20. <meta charset="UTF-8">
  21. <title>Upload Diagnostics</title>
  22. <style>
  23. body { font-family: Arial, sans-serif; margin: 20px; }
  24. .section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; }
  25. .warning { background-color: #fff3cd; border-color: #ffeaa7; }
  26. .error { background-color: #f8d7da; border-color: #f5c6cb; }
  27. .success { background-color: #d4edda; border-color: #c3e6cb; }
  28. .info { background-color: #d1ecf1; border-color: #bee5eb; }
  29. table { width: 100%; border-collapse: collapse; }
  30. th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
  31. th { background-color: #f2f2f2; }
  32. .test-btn { padding: 10px 20px; margin: 5px; cursor: pointer; }
  33. #results { margin-top: 20px; }
  34. </style>
  35. </head>
  36. <body>
  37. <h1>Upload Diagnostics Tool</h1>
  38. <div class="section info">
  39. <h2>PHP Upload Configuration</h2>
  40. <table>
  41. <tr><th>Setting</th><th>Current Value</th><th>Recommended</th><th>Status</th></tr>
  42. <?php
  43. $settings = [
  44. 'upload_max_filesize' => ['current' => ini_get('upload_max_filesize'), 'recommended' => '20M', 'description' => 'Maximum file upload size'],
  45. 'post_max_size' => ['current' => ini_get('post_max_size'), 'recommended' => '25M', 'description' => 'Maximum POST request size'],
  46. 'memory_limit' => ['current' => ini_get('memory_limit'), 'recommended' => '256M', 'description' => 'Memory limit for PHP'],
  47. 'max_execution_time' => ['current' => ini_get('max_execution_time'), 'recommended' => '300', 'description' => 'Maximum execution time (seconds)'],
  48. 'max_input_time' => ['current' => ini_get('max_input_time'), 'recommended' => '300', 'description' => 'Maximum input time (seconds)'],
  49. 'file_uploads' => ['current' => ini_get('file_uploads'), 'recommended' => 'On', 'description' => 'File uploads enabled'],
  50. 'max_file_uploads' => ['current' => ini_get('max_file_uploads'), 'recommended' => '20', 'description' => 'Maximum simultaneous file uploads']
  51. ];
  52. foreach ($settings as $key => $setting) {
  53. $current = $setting['current'];
  54. $recommended = $setting['recommended'];
  55. $status = 'success';
  56. $statusClass = 'success';
  57. if ($key === 'file_uploads') {
  58. if ($current !== '1' && strtolower($current) !== 'on') {
  59. $status = 'ERROR - File uploads disabled!';
  60. $statusClass = 'error';
  61. }
  62. } elseif ($key === 'upload_max_filesize') {
  63. $currentBytes = return_bytes($current);
  64. $recommendedBytes = return_bytes($recommended);
  65. if ($currentBytes < $recommendedBytes) {
  66. $status = 'WARNING - Too small';
  67. $statusClass = 'warning';
  68. }
  69. } elseif ($key === 'post_max_size') {
  70. $currentBytes = return_bytes($current);
  71. $recommendedBytes = return_bytes($recommended);
  72. if ($currentBytes < $recommendedBytes) {
  73. $status = 'WARNING - Should be larger than upload_max_filesize';
  74. $statusClass = 'warning';
  75. }
  76. }
  77. echo "<tr>
  78. <td>{$key}</td>
  79. <td>{$current}</td>
  80. <td>{$recommended}</td>
  81. <td class='{$statusClass}'>{$status}</td>
  82. </tr>";
  83. }
  84. ?>
  85. </table>
  86. </div>
  87. <div class="section info">
  88. <h2>Server Information</h2>
  89. <table>
  90. <tr><th>Item</th><th>Value</th></tr>
  91. <tr><td>PHP Version</td><td><?php echo PHP_VERSION; ?></td></tr>
  92. <tr><td>Web Server</td><td><?php echo $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'; ?></td></tr>
  93. <tr><td>Server API</td><td><?php echo PHP_SAPI; ?></td></tr>
  94. <tr><td>Document Root</td><td><?php echo $_SERVER['DOCUMENT_ROOT'] ?? 'Unknown'; ?></td></tr>
  95. <tr><td>Max Request Size (calculated)</td><td><?php echo min(return_bytes(ini_get('post_max_size')), return_bytes(ini_get('upload_max_filesize'))); ?> bytes</td></tr>
  96. </table>
  97. </div>
  98. <div class="section info">
  99. <h2>Upload Test</h2>
  100. <p>Test different file sizes to identify the exact limit:</p>
  101. <button class="test-btn" onclick="testUpload(100)">Test 100KB</button>
  102. <button class="test-btn" onclick="testUpload(500)">Test 500KB</button>
  103. <button class="test-btn" onclick="testUpload(1024)">Test 1MB</button>
  104. <button class="test-btn" onclick="testUpload(2048)">Test 2MB</button>
  105. <button class="test-btn" onclick="testUpload(5120)">Test 5MB</button>
  106. <button class="test-btn" onclick="testUpload(10240)">Test 10MB</button>
  107. <button class="test-btn" onclick="testUpload(20480)">Test 20MB</button>
  108. <div id="results"></div>
  109. </div>
  110. <div class="section info">
  111. <h2>Nginx Configuration Check</h2>
  112. <p><strong>Important:</strong> The error "client intended to send too large body" indicates an nginx limit.</p>
  113. <p>Check these nginx settings in your server configuration:</p>
  114. <ul>
  115. <li><code>client_max_body_size</code> - Default is 1MB, should be higher</li>
  116. <li><code>client_body_buffer_size</code> - Buffer size for request body</li>
  117. <li><code>client_header_timeout</code> - Timeout for client headers</li>
  118. <li><code>client_body_timeout</code> - Timeout for client body</li>
  119. </ul>
  120. <h3>Typical nginx configuration needed:</h3>
  121. <pre style="background: #f4f4f4; padding: 10px; border: 1px solid #ddd;">
  122. server {
  123. listen 80;
  124. server_name samuli.valavuo.net;
  125. root /path/to/website;
  126. index index.php;
  127. # Increase upload limits
  128. client_max_body_size 25M;
  129. client_body_buffer_size 128k;
  130. client_body_timeout 60s;
  131. location ~ \.php$ {
  132. fastcgi_pass unix:/var/run/php/php-fpm.sock;
  133. fastcgi_index index.php;
  134. include fastcgi_params;
  135. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  136. }
  137. }</pre>
  138. </div>
  139. <div class="section warning">
  140. <h2>Next Steps</h2>
  141. <ol>
  142. <li><strong>If nginx is the issue:</strong> Update your nginx configuration with <code>client_max_body_size 25M;</code> and restart nginx</li>
  143. <li><strong>If PHP is the issue:</strong> The .htaccess file should help, but you may need to update php.ini directly</li>
  144. <li><strong>Test again:</strong> After making changes, test with the buttons above</li>
  145. </ol>
  146. </div>
  147. <script>
  148. function testUpload(sizeKB) {
  149. const results = document.getElementById('results');
  150. results.innerHTML = '<p>Testing upload with ' + sizeKB + 'KB file...</p>';
  151. // Create test data
  152. const size = sizeKB * 1024;
  153. const data = new Uint8Array(size);
  154. for (let i = 0; i < size; i++) {
  155. data[i] = Math.floor(Math.random() * 256);
  156. }
  157. const blob = new Blob([data], { type: 'application/octet-stream' });
  158. const formData = new FormData();
  159. formData.append('test_file', blob, 'test_' + sizeKB + 'kb.dat');
  160. fetch('upload_diagnostic.php?action=test', {
  161. method: 'POST',
  162. body: formData
  163. })
  164. .then(response => response.json())
  165. .then(data => {
  166. const status = data.success ? 'success' : 'error';
  167. results.innerHTML = '<div class="section ' + status + '"><h3>Test Result: ' + sizeKB + 'KB</h3><pre>' + JSON.stringify(data, null, 2) + '</pre></div>';
  168. })
  169. .catch(error => {
  170. results.innerHTML = '<div class="section error"><h3>Test Failed: ' + sizeKB + 'KB</h3><p>' + error.message + '</p></div>';
  171. });
  172. }
  173. </script>
  174. </body>
  175. </html>
  176. <?php
  177. // Handle test upload
  178. if (isset($_GET['action']) && $_GET['action'] === 'test' && $_SERVER['REQUEST_METHOD'] === 'POST') {
  179. header('Content-Type: application/json');
  180. $result = [
  181. 'success' => false,
  182. 'size' => 0,
  183. 'error' => 'No file uploaded',
  184. 'php_info' => [
  185. 'upload_max_filesize' => ini_get('upload_max_filesize'),
  186. 'post_max_size' => ini_get('post_max_size'),
  187. 'memory_limit' => ini_get('memory_limit')
  188. ],
  189. 'server_info' => [
  190. 'content_length' => $_SERVER['CONTENT_LENGTH'] ?? 0,
  191. 'content_type' => $_SERVER['CONTENT_TYPE'] ?? 'unknown'
  192. ]
  193. ];
  194. if (isset($_FILES['test_file'])) {
  195. $file = $_FILES['test_file'];
  196. $result['size'] = $file['size'];
  197. $result['original_name'] = $file['name'];
  198. $result['type'] = $file['type'];
  199. $result['error_code'] = $file['error'];
  200. if ($file['error'] === UPLOAD_ERR_OK) {
  201. $result['success'] = true;
  202. $result['message'] = 'Upload successful';
  203. } else {
  204. $result['error'] = getUploadErrorMessage($file['error']);
  205. }
  206. }
  207. echo json_encode($result);
  208. exit;
  209. }
  210. function return_bytes($val) {
  211. $val = trim($val);
  212. $last = strtolower($val[strlen($val)-1]);
  213. $val = (int)$val;
  214. switch($last) {
  215. case 'g':
  216. $val *= 1024;
  217. case 'm':
  218. $val *= 1024;
  219. case 'k':
  220. $val *= 1024;
  221. }
  222. return $val;
  223. }
  224. function getUploadErrorMessage($errorCode) {
  225. switch ($errorCode) {
  226. case UPLOAD_ERR_INI_SIZE:
  227. return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
  228. case UPLOAD_ERR_FORM_SIZE:
  229. return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
  230. case UPLOAD_ERR_PARTIAL:
  231. return 'The uploaded file was only partially uploaded';
  232. case UPLOAD_ERR_NO_FILE:
  233. return 'No file was uploaded';
  234. case UPLOAD_ERR_NO_TMP_DIR:
  235. return 'Missing a temporary folder';
  236. case UPLOAD_ERR_CANT_WRITE:
  237. return 'Failed to write file to disk';
  238. case UPLOAD_ERR_EXTENSION:
  239. return 'A PHP extension stopped the file upload';
  240. default:
  241. return 'Unknown upload error';
  242. }
  243. }
  244. ?>