Monday, July 11, 2011

Mocking php://input

Using php://input in the code can lead to chalenges when the time to test comes (e.g. http://stackoverflow.com/questions/3221542/how-do-i-override-php-input-when-doing-unit-tests).

One way is to mock the behavior
class MockPhpStream{
protected $index = 0;
protected $length = null;
protected $data = 'hello world';

public $context;

function __construct(){
if(file_exists($this->buffer_filename())){
$this->data = file_get_contents($this->buffer_filename());
}else{
$this->data = '';
}
$this->index = 0;
$this->length = strlen($this->data);
}

protected function buffer_filename(){
return sys_get_temp_dir().'\php_input.txt';
}

function stream_open($path, $mode, $options, &$opened_path){
return true;
}

function stream_close(){
}

function stream_stat(){
return array();
}

function stream_flush(){
return true;
}

function stream_read($count){
if(is_null($this->length) === TRUE){
$this->length = strlen($this->data);
}
$length = min($count, $this->length - $this->index);
$data = substr($this->data, $this->index);
$this->index = $this->index + $length;
return $data;
}

function stream_eof(){
return ($this->index >= $this->length ? TRUE : FALSE);
}

function stream_write($data){
return file_put_contents($this->buffer_filename(), $data);
}

function unlink(){
if(file_exists($this->buffer_filename())){
unlink($this->buffer_filename());
}
$this->data = '';
$this->index = 0;
$this->length = 0;
}
}

This can be used this way:
stream_wrapper_unregister("php");
stream_wrapper_register("php", "MockPhpStream");
file_put_contents('php://input', $data);
...... // $data will be retrieve when calling file_get_contents('php://input')
$data = file_get_contents('php://input');
......
stream_wrapper_restore("php");

Hope this help.

4 comments:

  1. Thank you very very very much !

    ReplyDelete
  2. Thank you But there is one error in the code under ubuntu.

    return sys_get_temp_dir().'\php_input.txt'; should be
    return sys_get_temp_dir().'/php_input.txt';

    ReplyDelete