.png before decoding it with imagecreatefrompng(). Two * concurrent reports could collide on the same filename, and the shared, * predictable path was vulnerable to symlink races. The fix decodes the PNG * directly from memory with imagecreatefromstring() and drops the temp file * entirely. */ $reportsPath = dirname(__DIR__, 4) . '/lib/reports.php'; beforeEach(function () use ($reportsPath) { require_once $reportsPath; }); test('reports.php decodes PNG data in memory via imagecreatefromstring', function () use ($reportsPath) { $src = file_get_contents($reportsPath); expect($src)->not->toBeFalse('lib/reports.php must be readable'); expect($src)->toContain('imagecreatefromstring($png_data)'); }); test('png2jpeg no longer writes a predictable temp file', function () use ($reportsPath) { $src = file_get_contents($reportsPath); expect($src)->not->toBeFalse('lib/reports.php must be readable'); expect($src)->not->toContain("'/tmp/' . time() . '.png'") ->and($src)->not->toMatch('/\bfopen\s*\(\s*\$fn\b/') ->and($src)->not->toContain('imagecreatefrompng($fn)'); }); test('reports.php contains no fopen or predictable-path file writes', function () use ($reportsPath) { $src = file_get_contents($reportsPath); expect($src)->not->toBeFalse('lib/reports.php must be readable'); foreach (['png2jpeg', 'png2gif'] as $function) { $start = strpos($src, "function $function("); expect($start)->not->toBeFalse("$function() must exist"); $end = strpos($src, "\nfunction ", $start + 1); expect($end)->not->toBeFalse("$function() must have a following function"); $body = substr($src, $start, $end - $start); expect($body)->not->toMatch('/\bfopen\s*\(/') ->and($body)->not->toMatch('/\bfile_put_contents\s*\(\s*[\'"]\/tmp\//'); } }); test('png2jpeg round-trips a minimal valid PNG without touching disk', function () { if (!extension_loaded('gd') || !function_exists('imagecreate')) { test()->markTestSkipped('GD is not available'); } $im = imagecreate(1, 1); expect($im)->not->toBeFalse('GD must create the source image'); imagecolorallocate($im, 255, 0, 0); ob_start(); imagepng($im); $png = ob_get_clean(); $jpeg = png2jpeg($png); expect($jpeg)->toBeString() ->and($jpeg)->not->toBe('') ->and(substr($jpeg, 0, 2))->toBe("\xFF\xD8"); }); test('png2gif round-trips a minimal valid PNG without touching disk', function () { if (!extension_loaded('gd') || !function_exists('imagecreate')) { test()->markTestSkipped('GD is not available'); } $im = imagecreate(1, 1); expect($im)->not->toBeFalse('GD must create the source image'); imagecolorallocate($im, 255, 0, 0); ob_start(); imagepng($im); $png = ob_get_clean(); $gif = png2gif($png); expect($gif)->toBeString() ->and($gif)->not->toBe('') ->and(substr($gif, 0, 6))->toMatch('/^GIF8[79]a/'); });