Created
October 3, 2015 19:29
-
-
Save tzkmx/a4456b831dbfeb91b2d9 to your computer and use it in GitHub Desktop.
Mixing Stream Wrappers & filters to create custom and lightweight views of database
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
<?php | |
/** | |
* @author Jesus Franco Martinez <jefrancomix@gmail.com> | |
*/ | |
class DBStream { | |
/** | |
* | |
* @var mysqli | |
*/ | |
private $mysql; | |
/** | |
* | |
* @var mysqli_stmt | |
*/ | |
private $stmt; | |
private $position = 0; | |
private $size = 0; | |
/** | |
* | |
* @var mysqli_result | |
*/ | |
private $result; | |
/* | |
public function __construct() | |
{ | |
return true; | |
} | |
* | |
*/ | |
public function stream_open($path, $mode, $options, &$opath) | |
{ | |
$url = parse_url($path); | |
$url['path'] = array_slice(split('/', substr($url['path'], 1)), 0, 2); | |
//echo '<pre>', print_r($url, false), '</pre>'; | |
$this->mysql = new mysqli(DB_HOST, DB_USER, DB_PASS, $url['path'][0], DB_PORT); | |
if ($this->mysql->connect_errno) { | |
throw new Exception($this->mysql->connect_error, $this->mysql->connect_errno); | |
} | |
switch ($mode){ | |
case 'r' : | |
$this->result = $this->mysql->query('SELECT * FROM ' . implode('.', $url['path'])); | |
if ('mysqli_result' !== get_class($this->result)) { | |
$e = $this->mysql->error_list; | |
array_push($e, 'Unable to get data from: ' . implode('.', $url['path'])); | |
throw new Exception(implode("\n", $e), $this->mysql->errno); | |
} | |
$this->size = $this->result->num_rows; | |
break; | |
default : return false; | |
} | |
return true; | |
} | |
public function stream_read() | |
{ | |
$out = $this->result->fetch_row(); | |
$this->position++; | |
return implode(';;;', $out); | |
} | |
public function stream_tell() | |
{ | |
return $this->position; | |
} | |
public function stream_seek($offset, $whence) | |
{ | |
switch ($whence) { | |
case SEEK_SET: | |
if ($offset < $this->size) { | |
$this->position = $offset; | |
$this->result->data_seek($offset); | |
} | |
break; | |
case SEEK_CUR: | |
if ($offset >= 0) { | |
$this->position += $offset; | |
$this->result->data_seek($this->position); | |
return true; | |
} else { | |
return false; | |
} | |
break; | |
case SEEK_END: | |
if (($this->size + $offset) >= 0) { | |
$this->position += $offset; | |
$this->result->data_seek($this->position); | |
return true; | |
} else { | |
return false; | |
} | |
break; | |
default: | |
return false; | |
} | |
} | |
public function stream_eof() | |
{ | |
return ($this->position >= $this->size); | |
} | |
public function stream_close() | |
{ | |
$this->result->free(); | |
$this->mysql->close(); | |
} | |
public function stream_stat() | |
{ | |
$moment = time(); | |
return array( | |
0 => 0, | |
1 => 0, | |
2 => 0666, | |
3 => 0, | |
4 => 0, | |
5 => 0, | |
6 => 2, | |
7 => $this->size, | |
8 => $moment, | |
9 => $moment, | |
10 => $moment, | |
11 => -1, | |
12 => -1, | |
'dev' => 0, | |
'ino' => 0, | |
'mode' => 0666, | |
'nlink' => 0, | |
'uid' => 0, | |
'gid' => 0, | |
'rdev' => 0, | |
'size' => $this->size, | |
'atime' => $moment, | |
'mtime' => $moment, | |
'ctime' => $moment, | |
'blksize' => -1, | |
'blocks' => -1, | |
); | |
} | |
} |
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
<?php | |
require 'bootstrap.php'; | |
?> | |
<html> | |
<body> | |
<?php | |
stream_register_wrapper('db', 'DBStream', STREAM_IS_URL); | |
stream_filter_register('prewrap', 'WrapperFilter'); | |
try { | |
$fr=fopen('php://filter/read=prewrap/resource=db://user:pass@host/schema/table','r'); | |
echo stream_get_contents($fr); | |
fclose($fr); | |
} catch (Exception $e) { | |
echo $e->getCode() , ': ' , $e->getMessage(); | |
echo $e->getTraceAsString(); | |
} | |
?> | |
</body> | |
</html> |
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
<?php | |
/** | |
* Description of WrapperFilter | |
* | |
* @author Jesus Franco Martinez <jefrancomix@gmail.com> | |
*/ | |
class WrapperFilter extends php_user_filter { | |
private $rows = 0; | |
protected function wrapCell($item) | |
{ | |
return '<td>' . $item . '</td>'; | |
} | |
public function filter($in, $out, &$consumed, $closing) { | |
while ($bucket = stream_bucket_make_writeable($in)) { | |
//$d = ($this->rows === 0) ? 'HEADER TEXT' : ''; | |
$d = array_map(array($this, 'wrapCell'), split(';;;', $bucket->data)); | |
$bucket->data = '<tr id="' . $this->rows++ . '">' . implode('', $d) . '</tr>'; | |
$consumed += $bucket->datalen; | |
stream_bucket_append($out, $bucket); | |
} | |
return PSFS_PASS_ON; | |
} | |
public function onClose() { | |
echo '</table>'; | |
parent::onClose(); | |
} | |
public function onCreate() { | |
echo '<table>'; | |
parent::onCreate(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment