Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions main/UI/View/JsonPView.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php
/***************************************************************************
* Copyright (C) 2012 by Georgiy T. Kutsurua *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

/**
* @ingroup Flow
**/

class JsonPView extends JsonView
{
/**
* Javascript valid function name pattern
*/
const CALLBACK_PATTERN = '/^[\$A-Z_][0-9A-Z_\$]*$/i';

/**
* @static
* @return JsonPView
*/
public static function create()
{
return new self();
}

/**
* Callback function name
* @see http://en.wikipedia.org/wiki/JSONP
* @var string
*/
protected $callback = null;

/**
* @param mixed $callback
* @return JsonPView
*/
public function setCallback($callback)
{
$realCallbackName = null;

if(is_scalar($callback))
$realCallbackName = $callback;
elseif($callback instanceof Stringable)
$realCallbackName = $callback->toString();
else
throw new WrongArgumentException('undefined type of callback, gived "'.gettype($callback).'"');

if(!preg_match(static::CALLBACK_PATTERN, $realCallbackName))
throw new WrongArgumentException('invalid function name, you should set valid javascript function name! gived "'.$realCallbackName.'"');

$this->callback = $realCallbackName;

return $this;
}

/**
* @param Model $model
* @return string
*/
public function toString(/* Model */ $model = null)
{
Assert::isNotEmpty($this->callback, 'callback can not be empty!');

$json = parent::toString($model);

return $this->callback.'('.$json.');';
}

}
2 changes: 1 addition & 1 deletion main/UI/View/JsonView.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/**
* @ingroup Flow
**/
final class JsonView implements View, Stringable
class JsonView implements View, Stringable
{
protected $options = 0;

Expand Down
88 changes: 88 additions & 0 deletions main/UI/View/JsonXssView.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/***************************************************************************
* Copyright (C) 2012 by Georgiy T. Kutsurua *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

/**
* @ingroup Flow
**/

class JsonXssView extends JsonPView
{
/**
* Javascript valid function name pattern
*/
const CALLBACK_PATTERN = '/^[\$A-Z_][0-9A-Z_\$\.]*$/i';

/**
* Default prefix
* @var string
*/
protected $prefix = 'window.';

/**
* Default callback
* @var string
*/
protected $callback = 'name';

/**
* @static
* @return JsonXssView
*/
public static function create()
{
return new self();
}

/**
* @param $value
* @return JsonXssView
* @throws WrongArgumentException
*/
public function setPrefix($value)
{
if(!preg_match(static::CALLBACK_PATTERN, $value))
throw new WrongArgumentException('invalid prefix name, you should set valid javascript function name! gived "'.$value.'"');

$this->prefix = $value;

return $this;
}

/**
* @param Model $model
* @return string
*/
public function toString(/* Model */ $model = null)
{
/*
* Escaping warning datas
*/
$this->setHexAmp(true);
$this->setHexApos(true);
$this->setHexQuot(true);
$this->setHexTag(true);

$json = JsonView::toString($model);

$json = str_ireplace(
array('u0022', 'u0027'),
array('\u0022', '\u0027'),
$json
);

$result = '<script type="text/javascript">'."\n";
$result.="\t".$this->prefix.$this->callback.'=\''.$json.'\';'."\n";
$result.='</script>'."\n";

return $result;
}

}
99 changes: 99 additions & 0 deletions test/main/JsonPViewTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
/***************************************************************************
* Copyright (C) 2012 by Georgiy T. Kutsurua *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

final class JsonPViewTest extends TestCase
{
protected $array = array('<foo>',"'bar'",'"baz"','&blong&');


public function testMain()
{
$model = Model::create()->set('array', $this->array);
$data = array('array' => $this->array);
$callback = 'myFunc';

//setup
$view = JsonPView::create();

try{
// empty js callback function name
$view->toString($model);

$this->fail('empty callback javascript function name expected!');
} catch(WrongArgumentException $e) {}

try{
$view->setCallback('34_callback'); // invalid javascript function name

$this->fail('invalid javascript function name expected!');
} catch(WrongArgumentException $e) {}

$view->setCallback($callback);

$this->assertEquals($this->makeString($callback, $data), $view->toString($model) );

$simpleStringableObject = SimpleStringableObject::create()->setString($callback);

$view->setCallback($simpleStringableObject);

$this->assertEquals($this->makeString($callback, $data), $view->toString($model) );
}

/**
* @param $callback
* @param $data
* @return string
*/
protected function makeString($callback, $data)
{
return $callback.'('.json_encode(
$data
).');';
}

}

class SimpleStringableObject implements Stringable
{
protected $string = null;


/**
* @static
* @return SimpleStringableObject
*/
public static function create()
{
return new self();
}

/**
* @param $value
* @return SimpleStringableObject
*/
public function setString($value)
{
Assert::isString($value);

$this->string = $value;

return $this;
}

/**
* @return str
*/
public function toString()
{
return $this->string;
}
}
?>
69 changes: 69 additions & 0 deletions test/main/JsonXssViewTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/***************************************************************************
* Copyright (C) 2012 by Georgiy T. Kutsurua *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/

final class JsonXssViewTest extends TestCase
{
protected $array = array('<foo>',"'bar'",'"baz"','&blong&');

public function testMain()
{
$prefix = 'window.';
$callback = 'name';

$model = Model::create()->set('array', $this->array);
$data = array('array' => $this->array);

//setup
$view = JsonXssView::create();

$defaultString = $view->toString($model);

$this->assertEquals($defaultString, $this->makeString($prefix, $callback, $data) );


$prefix='window2.';
$callback='name2';

$view->setCallback($callback);
$view->setPrefix($prefix);

$customString = $view->toString($model);

$this->assertEquals($customString, $this->makeString($prefix, $callback, $data) );
}

/**
* @param $prefix
* @param $callback
* @return string
*/
protected function makeString($prefix, $callback, $data)
{
return '<script type="text/javascript">'."\n".
"\t".$prefix.$callback.'=\''.
str_ireplace(
array('u0022', 'u0027'),
array('\u0022', '\u0027'),
json_encode(
$data,
JSON_HEX_AMP |
JSON_HEX_APOS |
JSON_HEX_QUOT |
JSON_HEX_TAG
)
).
'\';'."\n".
'</script>'."\n";
}

}

?>