Skip to content

Commit 41f6edb

Browse files
committed
Merge pull request #79 from soloweb/jsonBasedFeature
JsonPView & JsonXssView
2 parents ab63f7c + d0c2d12 commit 41f6edb

File tree

5 files changed

+332
-1
lines changed

5 files changed

+332
-1
lines changed

main/UI/View/JsonPView.class.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
/***************************************************************************
3+
* Copyright (C) 2012 by Georgiy T. Kutsurua *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify *
6+
* it under the terms of the GNU Lesser General Public License as *
7+
* published by the Free Software Foundation; either version 3 of the *
8+
* License, or (at your option) any later version. *
9+
* *
10+
***************************************************************************/
11+
12+
/**
13+
* @ingroup Flow
14+
**/
15+
16+
class JsonPView extends JsonView
17+
{
18+
/**
19+
* Javascript valid function name pattern
20+
*/
21+
const CALLBACK_PATTERN = '/^[\$A-Z_][0-9A-Z_\$]*$/i';
22+
23+
/**
24+
* @static
25+
* @return JsonPView
26+
*/
27+
public static function create()
28+
{
29+
return new self();
30+
}
31+
32+
/**
33+
* Callback function name
34+
* @see http://en.wikipedia.org/wiki/JSONP
35+
* @var string
36+
*/
37+
protected $callback = null;
38+
39+
/**
40+
* @param mixed $callback
41+
* @return JsonPView
42+
*/
43+
public function setCallback($callback)
44+
{
45+
$realCallbackName = null;
46+
47+
if(is_scalar($callback))
48+
$realCallbackName = $callback;
49+
elseif($callback instanceof Stringable)
50+
$realCallbackName = $callback->toString();
51+
else
52+
throw new WrongArgumentException('undefined type of callback, gived "'.gettype($callback).'"');
53+
54+
if(!preg_match(static::CALLBACK_PATTERN, $realCallbackName))
55+
throw new WrongArgumentException('invalid function name, you should set valid javascript function name! gived "'.$realCallbackName.'"');
56+
57+
$this->callback = $realCallbackName;
58+
59+
return $this;
60+
}
61+
62+
/**
63+
* @param Model $model
64+
* @return string
65+
*/
66+
public function toString(/* Model */ $model = null)
67+
{
68+
Assert::isNotEmpty($this->callback, 'callback can not be empty!');
69+
70+
$json = parent::toString($model);
71+
72+
return $this->callback.'('.$json.');';
73+
}
74+
75+
}

main/UI/View/JsonView.class.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/**
1313
* @ingroup Flow
1414
**/
15-
final class JsonView implements View, Stringable
15+
class JsonView implements View, Stringable
1616
{
1717
protected $options = 0;
1818

main/UI/View/JsonXssView.class.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
/***************************************************************************
3+
* Copyright (C) 2012 by Georgiy T. Kutsurua *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify *
6+
* it under the terms of the GNU Lesser General Public License as *
7+
* published by the Free Software Foundation; either version 3 of the *
8+
* License, or (at your option) any later version. *
9+
* *
10+
***************************************************************************/
11+
12+
/**
13+
* @ingroup Flow
14+
**/
15+
16+
class JsonXssView extends JsonPView
17+
{
18+
/**
19+
* Javascript valid function name pattern
20+
*/
21+
const CALLBACK_PATTERN = '/^[\$A-Z_][0-9A-Z_\$\.]*$/i';
22+
23+
/**
24+
* Default prefix
25+
* @var string
26+
*/
27+
protected $prefix = 'window.';
28+
29+
/**
30+
* Default callback
31+
* @var string
32+
*/
33+
protected $callback = 'name';
34+
35+
/**
36+
* @static
37+
* @return JsonXssView
38+
*/
39+
public static function create()
40+
{
41+
return new self();
42+
}
43+
44+
/**
45+
* @param $value
46+
* @return JsonXssView
47+
* @throws WrongArgumentException
48+
*/
49+
public function setPrefix($value)
50+
{
51+
if(!preg_match(static::CALLBACK_PATTERN, $value))
52+
throw new WrongArgumentException('invalid prefix name, you should set valid javascript function name! gived "'.$value.'"');
53+
54+
$this->prefix = $value;
55+
56+
return $this;
57+
}
58+
59+
/**
60+
* @param Model $model
61+
* @return string
62+
*/
63+
public function toString(/* Model */ $model = null)
64+
{
65+
/*
66+
* Escaping warning datas
67+
*/
68+
$this->setHexAmp(true);
69+
$this->setHexApos(true);
70+
$this->setHexQuot(true);
71+
$this->setHexTag(true);
72+
73+
$json = JsonView::toString($model);
74+
75+
$json = str_ireplace(
76+
array('u0022', 'u0027'),
77+
array('\u0022', '\u0027'),
78+
$json
79+
);
80+
81+
$result = '<script type="text/javascript">'."\n";
82+
$result.="\t".$this->prefix.$this->callback.'=\''.$json.'\';'."\n";
83+
$result.='</script>'."\n";
84+
85+
return $result;
86+
}
87+
88+
}

test/main/JsonPViewTest.class.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
/***************************************************************************
3+
* Copyright (C) 2012 by Georgiy T. Kutsurua *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify *
6+
* it under the terms of the GNU Lesser General Public License as *
7+
* published by the Free Software Foundation; either version 3 of the *
8+
* License, or (at your option) any later version. *
9+
* *
10+
***************************************************************************/
11+
12+
final class JsonPViewTest extends TestCase
13+
{
14+
protected $array = array('<foo>',"'bar'",'"baz"','&blong&');
15+
16+
17+
public function testMain()
18+
{
19+
$model = Model::create()->set('array', $this->array);
20+
$data = array('array' => $this->array);
21+
$callback = 'myFunc';
22+
23+
//setup
24+
$view = JsonPView::create();
25+
26+
try{
27+
// empty js callback function name
28+
$view->toString($model);
29+
30+
$this->fail('empty callback javascript function name expected!');
31+
} catch(WrongArgumentException $e) {}
32+
33+
try{
34+
$view->setCallback('34_callback'); // invalid javascript function name
35+
36+
$this->fail('invalid javascript function name expected!');
37+
} catch(WrongArgumentException $e) {}
38+
39+
$view->setCallback($callback);
40+
41+
$this->assertEquals($this->makeString($callback, $data), $view->toString($model) );
42+
43+
$simpleStringableObject = SimpleStringableObject::create()->setString($callback);
44+
45+
$view->setCallback($simpleStringableObject);
46+
47+
$this->assertEquals($this->makeString($callback, $data), $view->toString($model) );
48+
}
49+
50+
/**
51+
* @param $callback
52+
* @param $data
53+
* @return string
54+
*/
55+
protected function makeString($callback, $data)
56+
{
57+
return $callback.'('.json_encode(
58+
$data
59+
).');';
60+
}
61+
62+
}
63+
64+
class SimpleStringableObject implements Stringable
65+
{
66+
protected $string = null;
67+
68+
69+
/**
70+
* @static
71+
* @return SimpleStringableObject
72+
*/
73+
public static function create()
74+
{
75+
return new self();
76+
}
77+
78+
/**
79+
* @param $value
80+
* @return SimpleStringableObject
81+
*/
82+
public function setString($value)
83+
{
84+
Assert::isString($value);
85+
86+
$this->string = $value;
87+
88+
return $this;
89+
}
90+
91+
/**
92+
* @return str
93+
*/
94+
public function toString()
95+
{
96+
return $this->string;
97+
}
98+
}
99+
?>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
/***************************************************************************
3+
* Copyright (C) 2012 by Georgiy T. Kutsurua *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify *
6+
* it under the terms of the GNU Lesser General Public License as *
7+
* published by the Free Software Foundation; either version 3 of the *
8+
* License, or (at your option) any later version. *
9+
* *
10+
***************************************************************************/
11+
12+
final class JsonXssViewTest extends TestCase
13+
{
14+
protected $array = array('<foo>',"'bar'",'"baz"','&blong&');
15+
16+
public function testMain()
17+
{
18+
$prefix = 'window.';
19+
$callback = 'name';
20+
21+
$model = Model::create()->set('array', $this->array);
22+
$data = array('array' => $this->array);
23+
24+
//setup
25+
$view = JsonXssView::create();
26+
27+
$defaultString = $view->toString($model);
28+
29+
$this->assertEquals($defaultString, $this->makeString($prefix, $callback, $data) );
30+
31+
32+
$prefix='window2.';
33+
$callback='name2';
34+
35+
$view->setCallback($callback);
36+
$view->setPrefix($prefix);
37+
38+
$customString = $view->toString($model);
39+
40+
$this->assertEquals($customString, $this->makeString($prefix, $callback, $data) );
41+
}
42+
43+
/**
44+
* @param $prefix
45+
* @param $callback
46+
* @return string
47+
*/
48+
protected function makeString($prefix, $callback, $data)
49+
{
50+
return '<script type="text/javascript">'."\n".
51+
"\t".$prefix.$callback.'=\''.
52+
str_ireplace(
53+
array('u0022', 'u0027'),
54+
array('\u0022', '\u0027'),
55+
json_encode(
56+
$data,
57+
JSON_HEX_AMP |
58+
JSON_HEX_APOS |
59+
JSON_HEX_QUOT |
60+
JSON_HEX_TAG
61+
)
62+
).
63+
'\';'."\n".
64+
'</script>'."\n";
65+
}
66+
67+
}
68+
69+
?>

0 commit comments

Comments
 (0)