======================================================================
POSESIF - MEDIA RETRIEVAL AUDIT
======================================================================
===== [1] PAUSE STORAGE WORKER CRON =====
Crontab backup:
/root/posesif-crontab-before-media-fix-20261004-144244.txt
Storage cron sekarang:
# PAUSED_MEDIA_RETRIEVAL_FIX * * * * * /opt/cpanel/ea-php85/root/usr/bin/php /home/posesif/app/bin/storage-worker.php 5 >> /home/posesif/storage/logs/storage-worker.log 2>&1
===== [2] STORAGE WORKER PROCESS =====
CATATAN:
Jika satu worker sedang aktif, kita biarkan batch itu selesai.
Cron berikutnya sudah dihentikan.
===== [3] MEDIA.PHP =====
/home/posesif/public_html/media.php | size=10280 | owner=posesif:posesif | mode=644 | modified=2026-10-03 12:31:47.537662366 +0700
--- FULL media.php ---
1 prepare("
104 SELECT
105 s.id,
106 s.account_id,
107 s.message_id,
108 s.object_type,
109 s.status,
110 s.local_path,
111 s.original_name,
112 s.mime_type,
113 s.size_bytes,
114 s.provider,
115 s.drive_file_id
116
117 FROM storage_objects s
118
119 INNER JOIN wa_accounts a
120 ON a.id=s.account_id
121
122 INNER JOIN messages m
123 ON m.id=s.message_id
124 AND m.account_id=s.account_id
125
126 WHERE s.id=?
127 AND a.owner_customer_id=?
128 AND s.message_id IS NOT NULL
129
130 AND s.object_type IN
131 (
132 'image',
133 'video',
134 'audio',
135 'document',
136 'thumbnail'
137 )
138
139 LIMIT 1
140 ");
141
142
143 $stmt->execute([
144 $id,
145 $customerId
146 ]);
147
148
149 $media=
150 $stmt->fetch(
151 PDO::FETCH_ASSOC
152 );
153
154
155 if(!$media){
156
157 media_fail(
158 404,
159 'Media tidak ditemukan.'
160 );
161 }
162
163
164 /*
165 |--------------------------------------------------------------------------
166 | LOCAL MEDIA
167 |--------------------------------------------------------------------------
168 |
169 | Status "pending" TIDAK berarti file belum tersedia.
170 | Pending saat ini berarti belum selesai dikirim ke Google Drive.
171 |--------------------------------------------------------------------------
172 */
173
174 $localPath=
175 trim(
176 (string)(
177 $media['local_path']
178 ?? ''
179 )
180 );
181
182
183 if($localPath===''){
184
185 media_fail(
186 404,
187 'File media belum tersedia di server.'
188 );
189 }
190
191
192 $storageRoot=
193 realpath(
194 '/home/posesif/storage'
195 );
196
197 $realPath=
198 realpath(
199 $localPath
200 );
201
202
203 if(
204 !$storageRoot
205 ||
206 !$realPath
207 ||
208 !str_starts_with(
209 $realPath,
210 $storageRoot.
211 DIRECTORY_SEPARATOR
212 )
213 ){
214
215 media_fail(
216 404,
217 'File media tidak tersedia.'
218 );
219 }
220
221
222 if(
223 !is_file(
224 $realPath
225 )
226 ||
227 !is_readable(
228 $realPath
229 )
230 ){
231
232 media_fail(
233 404,
234 'File media tidak tersedia.'
235 );
236 }
237
238
239 /*
240 |--------------------------------------------------------------------------
241 | MIME TYPE
242 |--------------------------------------------------------------------------
243 */
244
245 $mime=
246 trim(
247 (string)(
248 $media['mime_type']
249 ?? ''
250 )
251 );
252
253
254 /*
255 * Hindari header injection.
256 */
257 $mime=
258 str_replace(
259 [
260 "\r",
261 "\n"
262 ],
263 '',
264 $mime
265 );
266
267
268 if($mime===''){
269
270 $finfo=
271 new finfo(
272 FILEINFO_MIME_TYPE
273 );
274
275 $mime=
276 $finfo->file(
277 $realPath
278 )
279 ?: 'application/octet-stream';
280 }
281
282
283 /*
284 |--------------------------------------------------------------------------
285 | FILE NAME
286 |--------------------------------------------------------------------------
287 */
288
289 $fileName=
290 trim(
291 (string)(
292 $media['original_name']
293 ?? ''
294 )
295 );
296
297
298 if($fileName===''){
299
300 $fileName=
301 basename(
302 $realPath
303 );
304 }
305
306
307 $fallbackName=
308 preg_replace(
309 '/[^A-Za-z0-9._-]+/',
310 '_',
311 $fileName
312 );
313
314
315 if(
316 !$fallbackName
317 ||
318 $fallbackName===''
319 ){
320
321 $fallbackName=
322 'media';
323 }
324
325
326 $encodedName=
327 rawurlencode(
328 $fileName
329 );
330
331
332 $download=
333 isset(
334 $_GET['download']
335 )
336 &&
337 (string)$_GET['download']
338 ===
339 '1';
340
341
342 $disposition=
343 $download
344 ? 'attachment'
345 : 'inline';
346
347
348 /*
349 |--------------------------------------------------------------------------
350 | FILE SIZE
351 |--------------------------------------------------------------------------
352 */
353
354 $size=
355 filesize(
356 $realPath
357 );
358
359
360 if(
361 $size===false
362 ||
363 $size<0
364 ){
365
366 media_fail(
367 500,
368 'Ukuran file tidak dapat dibaca.'
369 );
370 }
371
372
373 /*
374 |--------------------------------------------------------------------------
375 | RESPONSE HEADERS
376 |--------------------------------------------------------------------------
377 */
378
379 header(
380 'X-Content-Type-Options: nosniff'
381 );
382
383 header(
384 'Cache-Control: private, no-store, max-age=0'
385 );
386
387 header(
388 'Pragma: no-cache'
389 );
390
391 header(
392 'Accept-Ranges: bytes'
393 );
394
395 header(
396 'Content-Type: '.
397 $mime
398 );
399
400 header(
401 'Content-Disposition: '.
402 $disposition.
403 '; filename="'.
404 addcslashes(
405 $fallbackName,
406 "\\\""
407 ).
408 '"; filename*=UTF-8\'\''.
409 $encodedName
410 );
411
412
413 /*
414 |--------------------------------------------------------------------------
415 | RANGE SUPPORT
416 |--------------------------------------------------------------------------
417 */
418
419 $start=0;
420 $end=max(
421 0,
422 $size-1
423 );
424
425 $statusCode=200;
426
427
428 $range=
429 $_SERVER[
430 'HTTP_RANGE'
431 ]
432 ?? '';
433
434
435 if(
436 $size>0
437 &&
438 is_string(
439 $range
440 )
441 &&
442 $range!==''
443 ){
444
445 if(
446 preg_match(
447 '/^bytes=(\d*)-(\d*)$/',
448 trim(
449 $range
450 ),
451 $match
452 )
453 ){
454
455 $first=
456 $match[1];
457
458 $last=
459 $match[2];
460
461
462 /*
463 |--------------------------------------------------------------------------
464 | bytes=-500
465 |--------------------------------------------------------------------------
466 */
467
468 if(
469 $first===''
470 &&
471 $last!==''
472 ){
473
474 $suffix=
475 (int)$last;
476
477
478 if($suffix<=0){
479
480 header(
481 'Content-Range: bytes */'.
482 $size
483 );
484
485 media_fail(
486 416,
487 'Range tidak valid.'
488 );
489 }
490
491
492 $start=
493 max(
494 0,
495 $size-$suffix
496 );
497
498 $end=
499 $size-1;
500
501 }else{
502
503 $start=
504 (int)$first;
505
506
507 if($last!==''){
508
509 $end=
510 min(
511 (int)$last,
512 $size-1
513 );
514
515 }else{
516
517 $end=
518 $size-1;
519 }
520 }
521
522
523 if(
524 $start<0
525 ||
526 $start>=$size
527 ||
528 $end<$start
529 ){
530
531 header(
532 'Content-Range: bytes */'.
533 $size
534 );
535
536 media_fail(
537 416,
538 'Range tidak valid.'
539 );
540 }
541
542
543 $statusCode=206;
544 }
545 }
546
547
548 $length=
549 $size===0
550 ? 0
551 : (
552 $end
553 -
554 $start
555 +
556 1
557 );
558
559
560 http_response_code(
561 $statusCode
562 );
563
564
565 if($statusCode===206){
566
567 header(
568 'Content-Range: bytes '.
569 $start.
570 '-'.
571 $end.
572 '/'.
573 $size
574 );
575 }
576
577
578 header(
579 'Content-Length: '.
580 $length
581 );
582
583
584 /*
585 |--------------------------------------------------------------------------
586 | Jangan lock session selama browser streaming video/audio.
587 |--------------------------------------------------------------------------
588 */
589
590 if(
591 session_status()
592 ===
593 PHP_SESSION_ACTIVE
594 ){
595
596 session_write_close();
597 }
598
599
600 /*
601 |--------------------------------------------------------------------------
602 | HEAD REQUEST
603 |--------------------------------------------------------------------------
604 */
605
606 if(
607 (
608 $_SERVER[
609 'REQUEST_METHOD'
610 ]
611 ?? 'GET'
612 )
613 ===
614 'HEAD'
615 ){
616
617 exit;
618 }
619
620
621 /*
622 |--------------------------------------------------------------------------
623 | STREAM FILE
624 |--------------------------------------------------------------------------
625 */
626
627 while(
628 ob_get_level()>0
629 ){
630
631 ob_end_clean();
632 }
633
634
635 set_time_limit(
636 0
637 );
638
639
640 $fp=
641 fopen(
642 $realPath,
643 'rb'
644 );
645
646
647 if(!$fp){
648
649 media_fail(
650 500,
651 'File tidak dapat dibuka.'
652 );
653 }
654
655
656 if($start>0){
657
658 fseek(
659 $fp,
660 $start
661 );
662 }
663
664
665 $remaining=
666 $length;
667
668 $chunkSize=
669 1024*1024;
670
671
672 while(
673 $remaining>0
674 &&
675 !feof(
676 $fp
677 )
678 ){
679
680 $read=
681 min(
682 $chunkSize,
683 $remaining
684 );
685
686
687 $buffer=
688 fread(
689 $fp,
690 $read
691 );
692
693
694 if(
695 $buffer===false
696 ||
697 $buffer===''
698 ){
699
700 break;
701 }
702
703
704 echo $buffer;
705
706
707 $remaining-=
708 strlen(
709 $buffer
710 );
711
712
713 flush();
714
715
716 if(
717 connection_aborted()
718 ){
719
720 break;
721 }
722 }
723
724
725 fclose(
726 $fp
727 );
728
729 exit;
===== [4] INBOX MEDIA REFERENCES =====
688: ON s.id=m.storage_object_id
2322:
2705
2706