Fix bug proxy (bad url encoding) + update depencies

This commit is contained in:
Frederic Guillot 2015-01-06 19:08:10 -05:00
parent 9f3d19bfc2
commit 0da3a8dfa3
14 changed files with 285 additions and 133 deletions

View File

@ -81,7 +81,7 @@ Router\get_action('select-db', function() {
// Image proxy (avoid SSL mixed content warnings)
Router\get_action('proxy', function() {
list($content, $type) = Model\Proxy\download(urldecode(Request\param('url')));
list($content, $type) = Model\Proxy\download(rawurldecode(Request\param('url')));
if (empty($content)) {
Response\text('Not Found', 404);

2
vendor/autoload.php vendored
View File

@ -4,4 +4,4 @@
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae::getLoader();
return ComposerAutoloaderInita57f23d5e3b273c0241536094b292083::getLoader();

View File

@ -56,7 +56,11 @@ class ClassLoader
public function getPrefixes()
{
return call_user_func_array('array_merge', $this->prefixesPsr0);
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae
class ComposerAutoloaderInita57f23d5e3b273c0241536094b292083
{
private static $loader;
@ -19,9 +19,9 @@ class ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInita57f23d5e3b273c0241536094b292083', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInita57f23d5e3b273c0241536094b292083', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
@ -42,14 +42,14 @@ class ComposerAutoloaderInit738d0ffba01de68eecc7cdccd108bcae
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $file) {
composerRequire738d0ffba01de68eecc7cdccd108bcae($file);
composerRequirea57f23d5e3b273c0241536094b292083($file);
}
return $loader;
}
}
function composerRequire738d0ffba01de68eecc7cdccd108bcae($file)
function composerRequirea57f23d5e3b273c0241536094b292083($file)
{
require $file;
}

View File

@ -123,18 +123,18 @@
"source": {
"type": "git",
"url": "https://github.com/fguillot/picoDb.git",
"reference": "8116698f9471f6c3f9b3c1334ee358c9b73d9864"
"reference": "268b3389d2bc3c92ef749a63440d17bd75e2a628"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/picoDb/zipball/8116698f9471f6c3f9b3c1334ee358c9b73d9864",
"reference": "8116698f9471f6c3f9b3c1334ee358c9b73d9864",
"url": "https://api.github.com/repos/fguillot/picoDb/zipball/268b3389d2bc3c92ef749a63440d17bd75e2a628",
"reference": "268b3389d2bc3c92ef749a63440d17bd75e2a628",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-01-02 16:42:20",
"time": "2015-01-03 00:32:58",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -162,18 +162,18 @@
"source": {
"type": "git",
"url": "https://github.com/fguillot/picoFeed.git",
"reference": "3ef98d7b1ea35bd48e0a4e99ea518d0c3165a0c0"
"reference": "627d1d48642ef82f8bb0e70870f36151b3c6936d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/3ef98d7b1ea35bd48e0a4e99ea518d0c3165a0c0",
"reference": "3ef98d7b1ea35bd48e0a4e99ea518d0c3165a0c0",
"url": "https://api.github.com/repos/fguillot/picoFeed/zipball/627d1d48642ef82f8bb0e70870f36151b3c6936d",
"reference": "627d1d48642ef82f8bb0e70870f36151b3c6936d",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-01-02 20:21:50",
"time": "2015-01-06 23:58:29",
"type": "library",
"installation-source": "dist",
"autoload": {

View File

@ -20,15 +20,16 @@ Requirements
- PDO
- A database: Sqlite, Mysql or Postgresql
Todo
----
- Add support for Distinct and group by
Documentation
-------------
## Connect to your database
### Installation
```bash
composer require fguillot/picodb dev-master
```
### Connect to your database
```php
use PicoDb\Database;
@ -48,19 +49,19 @@ Documentation
));
```
## Execute a SQL request
### Execute a SQL request
```php
$db->execute('CREATE TABLE toto (column1 TEXT)');
```
## Insert some data
### Insert some data
```php
$db->table('toto')->save(['column1' => 'hey']);
```
## Transations
### Transations
```php
$db->transaction(function($db) {
@ -69,7 +70,7 @@ Documentation
});
```
## Fetch all data
### Fetch all data
```php
$records = $db->table('toto')->findAll();
@ -79,19 +80,19 @@ Documentation
}
```
## Update something
### Update something
$db->table('toto')->eq('id', 1)->save(['column1' => 'hey']);
You just need to add a condition to perform an update.
## Remove rows
### Remove rows
```php
$db->table('toto')->lowerThan('column1', 10)->remove();
```
## Sorting
### Sorting
```php
$db->table('toto')->asc('column1')->findAll();
@ -103,20 +104,18 @@ or
$db->table('toto')->desc('column1')->findAll();
```
## Limit and offset
### Limit and offset
```php
$db->table('toto')->limit(10)->offset(5)->findAll();
```
## Fetch only some columns
### Fetch only some columns
```php
$db->table('toto')->columns('column1', 'column2')->findAll();
```
## Conditions
### Equals condition
```php
@ -248,9 +247,9 @@ How to make a OR condition:
->findAll();
```
## Schema migrations
### Schema migrations
### Define a migration
#### Define a migration
- Migrations are defined in simple functions inside a namespace named "Schema".
- An instance of PDO is passed to first argument of the function.
@ -285,7 +284,7 @@ Example:
}
```
### Run schema update automatically
#### Run schema update automatically
- The method "check()" executes all migrations until to reach the correct version number.
- If we are already on the last version nothing will happen.

View File

@ -6,6 +6,7 @@ use Closure;
use PDO;
use PDOException;
use LogicException;
use RuntimeException;
use Picodb\Driver\Sqlite;
use Picodb\Driver\Mysql;
use Picodb\Driver\Postgres;
@ -53,6 +54,14 @@ class Database
*/
public $log_queries = false;
/**
* Number of SQL queries executed
*
* @access public
* @var integer
*/
public $nb_queries = 0;
/**
* Constructor, iniatlize a PDO driver
*
@ -199,7 +208,7 @@ class Database
* @access public
* @param string $sql SQL query
* @param array $values Values
* @return PDOStatement
* @return PDOStatement|false
*/
public function execute($sql, array $values = array())
{
@ -220,11 +229,21 @@ class Database
$this->setLogMessage('DURATION='.(microtime(true) - $start));
}
$this->nb_queries++;
return $rq;
}
catch (PDOException $e) {
$this->cancelTransaction();
if (in_array($e->getCode(), $this->pdo->getDuplicateKeyErrorCode())) {
return false;
}
$this->setLogMessage($e->getMessage());
return false;
throw new RuntimeException('SQL error');
}
}
@ -237,23 +256,9 @@ class Database
*/
public function transaction(Closure $callback)
{
try {
$this->pdo->beginTransaction();
$result = $callback($this);
if ($result === false) {
$this->pdo->rollback();
}
else {
$this->pdo->commit();
}
}
catch (PDOException $e) {
$this->pdo->rollback();
$this->setLogMessage($e->getMessage());
$result = false;
}
$this->pdo->beginTransaction();
$result = $callback($this); // Rollback is done in the execute() method
$this->closeTransaction();
return $result === null ? true : $result;
}

View File

@ -81,4 +81,9 @@ class Mysql extends PDO
{
return 'LIKE';
}
public function getDuplicateKeyErrorCode()
{
return array(23000);
}
}

View File

@ -78,4 +78,9 @@ class Postgres extends PDO
{
return 'ILIKE';
}
public function getDuplicateKeyErrorCode()
{
return array(23505, 23503);
}
}

View File

@ -61,4 +61,9 @@ class Sqlite extends PDO
{
return 'LIKE';
}
public function getDuplicateKeyErrorCode()
{
return array(23000);
}
}

View File

@ -2,6 +2,8 @@
namespace PicoDb;
use PDO;
class Table
{
const SORT_ASC = 'ASC';
@ -19,27 +21,34 @@ class Table
private $values = array();
private $distinct = false;
private $group_by = array();
private $db;
/**
* Constructor
*
* @access public
* @param \PicoDb\Database $db
* @param string $table_name
*/
public function __construct(Database $db, $table_name)
{
$this->db = $db;
$this->table_name = $table_name;
return $this;
}
/**
* Insert or update
*
* @access public
* @param array $data
* @return boolean
*/
public function save(array $data)
{
if (! empty($this->conditions)) {
return $this->update($data);
}
else {
return $this->insert($data);
}
}
@ -47,7 +56,11 @@ class Table
/**
* Update
*
* Note: Do not use `rowCount()` the behaviour is different across drivers
* Note: Do not use `rowCount()` for update the behaviour is different across drivers
*
* @access public
* @param array $data
* @return boolean
*/
public function update(array $data)
{
@ -55,13 +68,11 @@ class Table
$values = array();
foreach ($data as $column => $value) {
$columns[] = $this->db->escapeIdentifier($column).'=?';
$values[] = $value;
}
foreach ($this->values as $value) {
$values[] = $value;
}
@ -72,18 +83,21 @@ class Table
$this->conditions()
);
$result = $this->db->execute($sql, $values);
return $result !== false;
return $this->db->execute($sql, $values) !== false;
}
/**
* Insert
*
* @access public
* @param array $data
* @return boolean
*/
public function insert(array $data)
{
$columns = array();
foreach ($data as $column => $value) {
$columns[] = $this->db->escapeIdentifier($column);
}
@ -94,10 +108,15 @@ class Table
implode(', ', array_fill(0, count($data), '?'))
);
return false !== $this->db->execute($sql, array_values($data));
return $this->db->execute($sql, array_values($data)) !== false;
}
/**
* Remove
*
* @access public
* @return boolean
*/
public function remove()
{
$sql = sprintf(
@ -107,49 +126,67 @@ class Table
);
$result = $this->db->execute($sql, $this->values);
return $result !== false && $result->rowCount() > 0;
return $result->rowCount() > 0;
}
/**
* Hashmap result [ [column1 => column2], [], ...]
*
* @access public
* @param string $key Column 1
* @param string $value Column 2
* @return array
*/
public function listing($key, $value)
{
$this->columns($key, $value);
$listing = array();
$results = $this->findAll();
if ($results) {
$this->columns($key, $value);
$rq = $this->db->execute($this->buildSelectQuery(), $this->values);
foreach ($results as $result) {
$rows = $rq->fetchAll(PDO::FETCH_NUM);
$listing[$result[$key]] = $result[$value];
}
foreach ($rows as $row) {
$listing[$row[0]] = $row[1];
}
return $listing;
}
/**
* Fetch all rows
*
* @access public
* @return array
*/
public function findAll()
{
$rq = $this->db->execute($this->buildSelectQuery(), $this->values);
if (false === $rq) return false;
return $rq->fetchAll(\PDO::FETCH_ASSOC);
return $rq->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Find all with a single column
*
* @access public
* @param string $column
* @return boolean
*/
public function findAllByColumn($column)
{
$this->columns = array($column);
$rq = $this->db->execute($this->buildSelectQuery(), $this->values);
if (false === $rq) return false;
return $rq->fetchAll(\PDO::FETCH_COLUMN, 0);
return $rq->fetchAll(PDO::FETCH_COLUMN, 0);
}
/**
* Fetch one row
*
* @access public
* @param array $data
* @return boolean
*/
public function findOne()
{
$this->limit(1);
@ -158,19 +195,29 @@ class Table
return isset($result[0]) ? $result[0] : null;
}
/**
* Fetch one column, first row
*
* @access public
* @param string $column
* @return string
*/
public function findOneColumn($column)
{
$this->limit(1);
$this->columns = array($column);
$rq = $this->db->execute($this->buildSelectQuery(), $this->values);
if (false === $rq) return false;
return $rq->fetchColumn();
}
/**
* Build a select query
*
* @access public
* @return string
*/
public function buildSelectQuery()
{
foreach ($this->columns as $key => $value) {
@ -191,7 +238,12 @@ class Table
);
}
/**
* Count
*
* @access public
* @return integer
*/
public function count()
{
$sql = sprintf(
@ -200,14 +252,22 @@ class Table
);
$rq = $this->db->execute($sql, $this->values);
if (false === $rq) return false;
$result = $rq->fetchColumn();
return $result ? (int) $result : 0;
}
public function join($table, $foreign_column, $local_column, $local_table = null)
/**
* Left join
*
* @access public
* @param string $table Join table
* @param string $foreign_column Foreign key on the join table
* @param string $local_column Local column
* @param string $local_table Local table
* @return \PicoDb\Table
*/
public function join($table, $foreign_column, $local_column, $local_table = '')
{
$this->joins[] = sprintf(
'LEFT JOIN %s ON %s=%s',
@ -219,55 +279,71 @@ class Table
return $this;
}
/**
* Build conditions
*
* @access public
* @return string
*/
public function conditions()
{
if (! empty($this->conditions)) {
return ' WHERE '.implode(' AND ', $this->conditions);
}
else {
return '';
}
return empty($this->conditions) ? '' : ' WHERE '.implode(' AND ', $this->conditions);
}
/**
* Add new condition
*
* @access public
* @param string $sql
*/
public function addCondition($sql)
{
if ($this->is_or_condition) {
$this->or_conditions[] = $sql;
}
else {
$this->conditions[] = $sql;
}
}
/**
* Start OR condition
*
* @access public
* @return \PicoDb\Table
*/
public function beginOr()
{
$this->is_or_condition = true;
$this->or_conditions = array();
return $this;
}
/**
* Close OR condition
*
* @access public
* @return \PicoDb\Table
*/
public function closeOr()
{
$this->is_or_condition = false;
if (! empty($this->or_conditions)) {
$this->conditions[] = '('.implode(' OR ', $this->or_conditions).')';
}
return $this;
}
/**
* Order by
*
* @access public
* @param string $column Column name
* @param string $order Direction ASC or DESC
* @return \PicoDb\Table
*/
public function orderBy($column, $order = self::SORT_ASC)
{
$order = strtoupper($order);
@ -283,7 +359,13 @@ class Table
return $this;
}
/**
* Ascending sort
*
* @access public
* @param string $column
* @return \PicoDb\Table
*/
public function asc($column)
{
if ($this->sql_order === '') {
@ -296,7 +378,13 @@ class Table
return $this;
}
/**
* Descending sort
*
* @access public
* @param string $column
* @return \PicoDb\Table
*/
public function desc($column)
{
if ($this->sql_order === '') {
@ -309,43 +397,83 @@ class Table
return $this;
}
/**
* Limit
*
* @access public
* @param integer $value
* @return \PicoDb\Table
*/
public function limit($value)
{
if (! is_null($value)) $this->sql_limit = ' LIMIT '.(int) $value;
if (! is_null($value)) {
$this->sql_limit = ' LIMIT '.(int) $value;
}
return $this;
}
/**
* Offset
*
* @access public
* @param integer $value
* @return \PicoDb\Table
*/
public function offset($value)
{
if (! is_null($value)) $this->sql_offset = ' OFFSET '.(int) $value;
if (! is_null($value)) {
$this->sql_offset = ' OFFSET '.(int) $value;
}
return $this;
}
/**
* Group by
*
* @access public
* @return \PicoDb\Table
*/
public function groupBy()
{
$this->group_by = \func_get_args();
$this->group_by = func_get_args();
return $this;
}
/**
* Define the columns for the select
*
* @access public
* @return \PicoDb\Table
*/
public function columns()
{
$this->columns = \func_get_args();
$this->columns = func_get_args();
return $this;
}
/**
* Distinct
*
* @access public
* @return \PicoDb\Table
*/
public function distinct()
{
$this->columns = \func_get_args();
$this->columns = func_get_args();
$this->distinct = true;
return $this;
}
/**
* Magic method for sql conditions
*
* @access public
* @param string $name
* @param array $arguments
* @return \PicoDb\Table
*/
public function __call($name, array $arguments)
{
$column = $arguments[0];

View File

@ -30,7 +30,8 @@ There two different ways to use this feature, define a proxy url or a callback.
### Define a proxy url
A proxy url must be defined with a placeholder `%s`.
The placeholder will be replaced by the image source urlencoded.
The placeholder will be replaced by the image source url encoded (RFC 3986).
In PHP, the url can be decoded with the function `rawurldecode()`.
```php
$config = new Config;
@ -55,7 +56,7 @@ $config = new Config;
$config->setFilterImageProxyCallback(function ($image_url) {
$key = hash_hmac('sha1', $image_url, 'secret');
return 'https://mypublicproxy/'.$key.'/'.urlencode($image_url);
return 'https://mypublicproxy/'.$key.'/'.rawurlencode($image_url);
});
```

View File

@ -389,7 +389,7 @@ class Attribute
if ($tag === 'img' && $attribute === 'src') {
if ($this->image_proxy_url) {
$value = sprintf($this->image_proxy_url, urlencode($value));
$value = sprintf($this->image_proxy_url, rawurlencode($value));
}
else if (is_callable($this->image_proxy_callback)) {
$value = call_user_func($this->image_proxy_callback, $value);

View File

@ -64,18 +64,18 @@ class AttributeFilterTest extends PHPUnit_Framework_TestCase
$filter->setImageProxyUrl('https://myproxy/?u=%s');
$url = 'http://example.net/image.png';
$this->assertTrue($filter->rewriteImageProxyUrl('img', 'src', $url));
$this->assertEquals('https://myproxy/?u='.urlencode('http://example.net/image.png'), $url);
$this->assertEquals('https://myproxy/?u='.rawurlencode('http://example.net/image.png'), $url);
$filter = new Attribute(new Url('http://www.la-grange.net'));
$filter->setImageProxyCallback(function ($image_url) {
$key = hash_hmac('sha1', $image_url, 'secret');
return 'https://mypublicproxy/'.$key.'/'.urlencode($image_url);
return 'https://mypublicproxy/'.$key.'/'.rawurlencode($image_url);
});
$url = 'http://example.net/image.png';
$this->assertTrue($filter->rewriteImageProxyUrl('img', 'src', $url));
$this->assertEquals('https://mypublicproxy/d9701029b054f6e178ef88fcd3c789365e52a26d/'.urlencode('http://example.net/image.png'), $url);
$this->assertEquals('https://mypublicproxy/d9701029b054f6e178ef88fcd3c789365e52a26d/'.rawurlencode('http://example.net/image.png'), $url);
}
public function testRewriteAbsoluteUrl()