forked from WordPress/playground-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
PHP: Output stdout and stderr to files instead of streams
Replaces output streams with temporary files to fix the following test case: ``` ● PHP › should echo bytes expect( php.run('<?php echo chr(1).chr(0).chr(1).chr(0).chr(2);').stdout ).toBe('\x01\x00\x01\x00\x02'); Expected: "1 0 1 0 2" Received: "1 1 2" ``` Turns out Emscripten has special semantics for null bytes in stdout and doesn't pass them to JavaScript handlers. This commit ditches stdout and stderr as a transport, and moves to temporary files instead. This way the null bytes output by PHP make it unchanged to the browser. One other change to enable that is upgrading the PHPOutput.stdout datatype from string to ArrayBuffer to make sure the bytes are passed around correctly. Solves WordPress#80
- Loading branch information
Showing
7 changed files
with
176 additions
and
53 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import * as phpLoaderModule from '../../../build/php.node.js'; | ||
import { startPHP } from '../php'; | ||
|
||
const { TextEncoder, TextDecoder } = require('util'); | ||
global.TextEncoder = TextEncoder; | ||
global.TextDecoder = TextDecoder; | ||
|
||
describe('PHP – boot', () => { | ||
it('should boot', async () => { | ||
const php = await startPHP(phpLoaderModule, 'NODE'); | ||
expect(php.run('<?php echo "1";')).toEqual({ | ||
stdout: '1', | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
}); | ||
}); | ||
|
||
describe('PHP ', () => { | ||
let php; | ||
beforeAll(async () => { | ||
php = await startPHP(phpLoaderModule, 'NODE'); | ||
}); | ||
|
||
it('should output strings (1)', async () => { | ||
expect(php.run('<?php echo "Hello world!";')).toEqual({ | ||
stdout: 'Hello world!', | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
}); | ||
it('should output strings (2) ', async () => { | ||
expect(php.run('<?php echo "Hello world!\nI am PHP";')).toEqual({ | ||
stdout: 'Hello world!\nI am PHP', | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
}); | ||
it('should output bytes ', async () => { | ||
const results = php.run( | ||
'<?php echo chr(1).chr(0).chr(1).chr(0).chr(2);' | ||
); | ||
expect({ | ||
...results, | ||
stdout: bytesStringToHumanReadable(results.stdout), | ||
}).toEqual({ | ||
stdout: bytesStringToHumanReadable('\x01\x00\x01\x00\x02'), | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
}); | ||
it('should output strings when .run() is called twice', async () => { | ||
expect(php.run('<?php echo "Hello world!";')).toEqual({ | ||
stdout: 'Hello world!', | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
|
||
expect(php.run('<?php echo "Ehlo world!";')).toEqual({ | ||
stdout: 'Ehlo world!', | ||
stderr: [''], | ||
exitCode: 0, | ||
}); | ||
}); | ||
it('should output data to stderr', async () => { | ||
const code = `<?php | ||
$stdErr = fopen('php://stderr', 'w'); | ||
fwrite($stdErr, "Hello from stderr!"); | ||
`; | ||
expect(php.run(code)).toEqual({ | ||
stdout: '', | ||
stderr: ['Hello from stderr!'], | ||
exitCode: 0, | ||
}); | ||
}); | ||
it('should output data to stderr in the shutdown handler', async () => { | ||
const code = `<?php | ||
$stdErr = fopen('php://stderr', 'w'); | ||
$errors = []; | ||
register_shutdown_function(function() use($stdErr){ | ||
fwrite($stdErr, "Hello from stderr!"); | ||
}); | ||
`; | ||
expect(php.run(code)).toEqual({ | ||
stdout: '', | ||
stderr: ['Hello from stderr!'], | ||
exitCode: 0, | ||
}); | ||
}); | ||
}); | ||
|
||
function bytesStringToHumanReadable(bytes) { | ||
return bytes | ||
.split('') | ||
.map((byte) => byte.charCodeAt(0)) | ||
.join(' '); | ||
} | ||
// echo chr(1).chr(0).chr(0).chr(5); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.