upload_diagnostic.php 11 KB

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