diff --git a/.gitignore b/.gitignore index eb8c905..157ad33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ +/composer.lock /composer.phar /tags /vendor config/config.php # phpstorm files -.idea/ \ No newline at end of file +.idea/ diff --git a/composer.json b/composer.json index 01e53f5..2f73538 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ } }, "require": { - "php": ">=5.3.0" + "php": ">=5.3.0", + "paragonie/random_compat": ">=2.0" }, "suggest": { "ext-xhprof": "You need to install either xhprof or uprofiler to use XHGui.", @@ -22,6 +23,7 @@ "ext-mongo": "Mongo is needed to store profiler results for PHP < 7.", "ext-mongodb": "Mongo is needed to store profiler results for PHP > 7.", "ext-curl": "You need to install the curl extension to upload saved files", + "ext-pdo": "You need to install the pdo extension to store profiler results to a relational database", "alcaeus/mongo-php-adapter": "Mongo PHP Adapter is required for PHP >7 (when using ext-mongodb)" } } diff --git a/config/config.default.php b/config/config.default.php index 07146b8..558fe21 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -34,6 +34,13 @@ 'db.host' => sprintf('mongodb://%s', $mongoUri), 'db.db' => $mongoDb, + 'pdo' => array( + 'dsn' => 'sqlite:/tmp/xhgui.sqlite3', + 'user' => null, + 'pass' => null, + 'table' => 'results' + ), + // Allows you to pass additional options like replicaSet to MongoClient. // 'username', 'password' and 'db' (where the user is added) 'db.options' => array(), diff --git a/external/header.php b/external/header.php index 9f2805e..76c2609 100644 --- a/external/header.php +++ b/external/header.php @@ -161,13 +161,8 @@ function () { $requestTimeFloat[1] = 0; } - if (Xhgui_Config::read('save.handler') === 'mongodb') { - $requestTs = new MongoDate($time); - $requestTsMicro = new MongoDate($requestTimeFloat[0], $requestTimeFloat[1]); - } else { - $requestTs = array('sec' => $time, 'usec' => 0); - $requestTsMicro = array('sec' => $requestTimeFloat[0], 'usec' => $requestTimeFloat[1]); - } + $requestTs = array('sec' => $time, 'usec' => 0); + $requestTsMicro = array('sec' => $requestTimeFloat[0], 'usec' => $requestTimeFloat[1]); $data['meta'] = array( 'url' => $uri, diff --git a/src/Xhgui/Saver.php b/src/Xhgui/Saver.php index d394085..3a28735 100644 --- a/src/Xhgui/Saver.php +++ b/src/Xhgui/Saver.php @@ -11,12 +11,11 @@ class Xhgui_Saver * Get a saver instance based on configuration data. * * @param array $config The configuration data. - * @return Xhgui_Saver_File|Xhgui_Saver_Mongo|Xhgui_Saver_Upload + * @return Xhgui_Saver_Interface */ public static function factory($config) { switch ($config['save.handler']) { - case 'file': return new Xhgui_Saver_File($config['save.handler.filename']); @@ -30,6 +29,16 @@ public static function factory($config) $timeout ); + case 'pdo': + return new Xhgui_Saver_Pdo( + new PDO( + $config['pdo']['dsn'], + $config['pdo']['user'], + $config['pdo']['pass'] + ), + $config['pdo']['table'] + ); + case 'mongodb': default: $mongo = new MongoClient($config['db.host'], $config['db.options']); diff --git a/src/Xhgui/Saver/Mongo.php b/src/Xhgui/Saver/Mongo.php index e9d2d17..74eb4fa 100644 --- a/src/Xhgui/Saver/Mongo.php +++ b/src/Xhgui/Saver/Mongo.php @@ -19,7 +19,21 @@ public function __construct(MongoCollection $collection) public function save(array $data) { - $data['_id'] = self::getLastProfilingId(); + if (!isset($data['_id'])) { + $data['_id'] = self::getLastProfilingId(); + } + + if (isset($data['meta']['request_ts'])) { + $data['meta']['request_ts'] = new MongoDate($data['meta']['request_ts']['sec']); + } + + if (isset($data['meta']['request_ts_micro'])) { + $data['meta']['request_ts_micro'] = new MongoDate( + $data['meta']['request_ts_micro']['sec'], + $data['meta']['request_ts_micro']['usec'] + ); + } + return $this->_collection->insert($data, array('w' => 0)); } diff --git a/src/Xhgui/Saver/Pdo.php b/src/Xhgui/Saver/Pdo.php new file mode 100644 index 0000000..81ae7e7 --- /dev/null +++ b/src/Xhgui/Saver/Pdo.php @@ -0,0 +1,105 @@ +exec(sprintf(self::TABLE_DDL, $table)); + + $this->stmt = $pdo->prepare(sprintf(self::INSERT_DML, $table)); + } + + public function save(array $data) + { + $main = $data['profile']['main()']; + + $this->stmt->execute(array( + 'id' => Xhgui_Util::generateId(), + 'profile' => json_encode($data['profile']), + 'url' => $data['meta']['url'], + 'SERVER' => json_encode($data['meta']['SERVER']), + 'GET' => json_encode($data['meta']['get']), + 'ENV' => json_encode($data['meta']['env']), + 'simple_url' => $data['meta']['simple_url'], + 'request_ts' => $data['meta']['request_ts']['sec'], + 'request_ts_micro' => "{$data['meta']['request_ts_micro']['sec']}.{$data['meta']['request_ts_micro']['usec']}", + 'request_date' => $data['meta']['request_date'], + 'main_wt' => $main['wt'], + 'main_ct' => $main['ct'], + 'main_cpu' => $main['cpu'], + 'main_mu' => $main['mu'], + 'main_pmu' => $main['pmu'], + )); + + $this->stmt->closeCursor(); + } +} diff --git a/src/Xhgui/Util.php b/src/Xhgui/Util.php index 5c35648..5c1711b 100644 --- a/src/Xhgui/Util.php +++ b/src/Xhgui/Util.php @@ -20,4 +20,18 @@ public static function simpleUrl($url) return preg_replace('/\=\d+/', '', $url); } + /** + * Returns an new ObjectId-like string, where its first 8 + * characters encode the current unix timestamp and the + * next 16 are random. + * + * @see http://php.net/manual/en/mongodb-bson-objectid.construct.php + * + * @return string + */ + public static function generateId() + { + return dechex(time()) . bin2hex(random_bytes(8)); + } + }