Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of git://github.com/Spoon/library into fix-smtp…

…-helo
  • Loading branch information...
commit ebb581415eb668096ef91409ee96cb18f0a62959 2 parents c7e9f78 + ebf2946
@annelyze annelyze authored
Showing with 3,945 additions and 772 deletions.
  1. +4 −0 spoon/CHANGELOG
  2. +2 −2 spoon/cookie/cookie.php
  3. +32 −8 spoon/database/database.php
  4. +42 −9 spoon/datagrid/datagrid.php
  5. +1 −1  spoon/datagrid/datagrid.tpl
  6. +12 −4 spoon/directory/directory.php
  7. +8 −2 spoon/email/email.php
  8. +4 −0 spoon/email/smtp.php
  9. +796 −0 spoon/feed/atom_rss.php
  10. +638 −0 spoon/feed/atom_rss_item.php
  11. +4 −4 spoon/feed/rss.php
  12. +5 −3 spoon/file/csv.php
  13. +9 −4 spoon/file/file.php
  14. +87 −61 spoon/filter/filter.php
  15. +3 −3 spoon/form/date.php
  16. +43 −34 spoon/form/dropdown.php
  17. +6 −0 spoon/form/element.php
  18. +8 −2 spoon/form/form.php
  19. +1 −1  spoon/form/hidden.php
  20. +2 −2 spoon/form/password.php
  21. +1 −1  spoon/form/radiobutton.php
  22. +35 −2 spoon/form/text.php
  23. +2 −2 spoon/form/textarea.php
  24. +6 −5 spoon/form/time.php
  25. +25 −18 spoon/http/http.php
  26. +1,367 −0 spoon/ical/ical.php
  27. +7 −1 spoon/rest/client.php
  28. +11 −2 spoon/spoon.php
  29. +3 −1 spoon/template/compiler.php
  30. +1 −1  spoon/template/modifiers.php
  31. +12 −14 tests/spoon_test.php → spoon/tests/SpoonTest.php
  32. +5 −15 tests/cookie/spoon_cookie_test.php → spoon/tests/cookie/SpoonCookieTest.php
  33. +59 −6 tests/database/spoon_database_test.php → spoon/tests/database/SpoonDatabaseTest.php
  34. +5 −3 tests/datagrid/spoon_datagrid_test.php → spoon/tests/datagrid/SpoonDataGridTest.php
  35. +6 −6 tests/date/spoon_date_test.php → spoon/tests/date/SpoonDateTest.php
  36. +6 −9 tests/directory/spoon_directory_test.php → spoon/tests/directory/SpoonDirectoryTest.php
  37. +5 −3 tests/feed/spoon_feed_rss_test.php → spoon/tests/feed/SpoonFeedRSSTest.php
  38. +38 −0 spoon/tests/file/SpoonFileTest.php
  39. +5 −5 tests/filter/spoon_filter_is_url_test.php → spoon/tests/filter/SpoonFilterIsURLTest.php
  40. +11 −12 tests/filter/spoon_filter_test.php → spoon/tests/filter/SpoonFilterTest.php
  41. +5 −6 tests/form/spoon_form_file_test.php → spoon/tests/form/SpoonFileFieldTest.php
  42. +5 −13 tests/form/spoon_form_button_test.php → spoon/tests/form/SpoonFormButtonTest.php
  43. +27 −9 tests/form/spoon_form_checkbox_test.php → spoon/tests/form/SpoonFormCheckboxTest.php
  44. +22 −15 tests/form/spoon_form_date_test.php → spoon/tests/form/SpoonFormDateTest.php
  45. +42 −11 tests/form/spoon_form_dropdown_test.php → spoon/tests/form/SpoonFormDropdownTest.php
  46. +10 −7 tests/form/spoon_form_hidden_test.php → spoon/tests/form/SpoonFormHiddenTest.php
  47. +10 −12 tests/form/spoon_form_multi_checkbox_test.php → spoon/tests/form/SpoonFormMultiCheckBoxTest.php
  48. +32 −19 tests/form/spoon_form_password_test.php → spoon/tests/form/SpoonFormPasswordTest.php
  49. +57 −0 spoon/tests/form/SpoonFormRadiobuttonTest.php
  50. +4 −7 tests/form/spoon_form_test.php → spoon/tests/form/SpoonFormTest.php
  51. +294 −0 spoon/tests/form/SpoonFormTextTest.php
  52. +28 −17 tests/form/spoon_form_textarea_test.php → spoon/tests/form/SpoonFormTextareaTest.php
  53. +18 −13 tests/form/spoon_form_time_test.php → spoon/tests/form/SpoonFormTimeTest.php
  54. +5 −3 tests/locale/spoon_locale_test.php → spoon/tests/locale/SpoonLocaleTest.php
  55. +15 −20 tests/log/spoon_log_test.php → spoon/tests/log/SpoonLogTest.php
  56. +6 −7 tests/rest/spoon_rest_client_test.php → spoon/tests/rest/SpoonRESTClientTest.php
  57. +23 −22 tests/template/spoon_modifiers_test.php → spoon/tests/template/SpoonModifiersTest.php
  58. +5 −3 tests/template/spoon_template_test.php → spoon/tests/template/SpoonTemplateTest.php
  59. +19 −0 spoon/tests/thumbnail/SpoonThumbnailTest.php
  60. 0  { → spoon}/tests/tmp/spoon.gif
  61. 0  { → spoon}/tests/tmp/spoon.jpg
  62. +1 −1  spoon/thumbnail/thumbnail.php
  63. +0 −42 tests/file/spoon_file_test.php
  64. +0 −37 tests/form/spoon_form_radiobutton_test.php
  65. +0 −244 tests/form/spoon_form_text_test.php
  66. +0 −18 tests/thumbnail/spoon_thumbnail_test.php
View
4 spoon/CHANGELOG
@@ -13,6 +13,10 @@
- SpoonFormTime::isValid now is a bit more precise and doesn't allow extra characters.
- Added some basic getters to SpoonDatabase
- SpoonFormDropDown will now allow you to combine option groups and regular values.
+- Fixed XSS vulnerability in SpoonForm.
+- Bugfix: Removes bare LFs so mailservers don't freak out.
+- Bugfix: invalid variable. (thx to Rafael den Heijer).
+
1.3.0 (2011-02-18)
----
View
4 spoon/cookie/cookie.php
@@ -46,7 +46,7 @@ public static function delete()
unset($_COOKIE[(string) $key]);
// unset cookie
- setcookie((string) $key, null, time() - 3600);
+ setcookie((string) $key, null, 1);
}
}
@@ -57,7 +57,7 @@ public static function delete()
unset($_COOKIE[(string) $argument]);
// unset cookie
- setcookie((string) $argument, null, time() - 3600);
+ setcookie((string) $argument, null, 1);
}
}
}
View
40 spoon/database/database.php
@@ -132,13 +132,26 @@ private function connect()
{
try
{
- // build dsn
- if($this->port !== null) $dsn = $this->driver . ':host=' . $this->hostname . ';port=' . $this->port . ';dbname=' . $this->database;
- else $dsn = $this->driver . ':host=' . $this->hostname . ';dbname=' . $this->database;
+ $dsn = $this->driver;
+ $dsn .= ':host=' . $this->hostname;
+ $dsn .= ';dbname=' . $this->database;
+ $dsn .= ';user=' . $this->username;
+ $dsn .= ';password=' . $this->password;
+
+ if($this->port !== null)
+ {
+ $dsn .= ';port=' . $this->port;
+ }
// create handler
$this->handler = new PDO($dsn, $this->username, $this->password);
$this->handler->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ // mysql only option
+ if($this->driver == 'mysql')
+ {
+ $this->handler->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
+ }
}
catch(PDOException $e)
@@ -146,9 +159,6 @@ private function connect()
throw new SpoonDatabaseException('A database connection could not be established.', 0, $this->password);
}
}
-
- // set nasty option
- $this->handler->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
}
@@ -787,7 +797,7 @@ public function insert($table, array $values)
$subKeys = array_keys($actualValues[0]);
// prefix with table name
- array_walk($subKeys, create_function('&$key', '$key = "' . $this->quoteName($table) . '.$key";'));
+ array_walk($subKeys, array($this, 'prefixTableNames'), $table);
// build query
$query .= implode(', ', $subKeys) . ') VALUES ';
@@ -835,7 +845,7 @@ public function insert($table, array $values)
$numFields = count($actualValues);
// prefix with table name
- array_walk($keys, create_function('&$key', '$key = "' . $this->quoteName($table) . '.$key";'));
+ array_walk($keys, array($this, 'prefixTableNames'), $table);
// build query
$query .= implode(', ', $keys) . ') VALUES (';
@@ -904,6 +914,20 @@ public function optimize($tables)
/**
+ * Prefix table names.
+ *
+ * @param string $key The key to be prefixed.
+ * @param string $value The value
+ * @param string $table The table name to prefix the key with.
+ * @return void
+ */
+ protected function prefixTableNames(&$key, $value, $table)
+ {
+ $key = $this->quoteName($table) . '.' . $key;
+ }
+
+
+ /**
* Quote the name of a table or column.
* Note: for now this will only put backticks around the name (mysql).
*
View
51 spoon/datagrid/datagrid.php
@@ -817,7 +817,7 @@ private function parseBody(array $records)
$this->parseRowFunctions($record, $this->attributes['row']);
// reset row
- $row = array('attributes' => '', 'oddAttributes' => '', 'evenAttributes' => '', 'columns' => array());
+ $row = array('attributes' => '', 'columns' => array());
// row attributes
$row['attributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row']));
@@ -836,10 +836,41 @@ private function parseBody(array $records)
else $row['attributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row']));
// odd row attributes (reversed since the first $i = 0)
- if(!SpoonFilter::isOdd($i)) $row['oddAttributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_odd']));
+ if(!SpoonFilter::isOdd($i)) $cycleAttributes = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_odd']));
// even row attributes
- else $row['evenAttributes'] = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_even']));
+ else $cycleAttributes = str_replace($record['labels'], $record['values'], $this->getHtmlAttributes($this->attributes['row_even']));
+
+ // no longer overwrite default attributes with odd/even attributes.
+ if(!empty($row['attributes']))
+ {
+ $cycleData = array();
+ $rowData = array();
+ preg_match_all('/( (.*?)=\"(.*?)\")/', $row['attributes'], $rowData);
+ preg_match_all('/( (.*?)=\"(.*?)\")/', $cycleAttributes, $cycleData);
+
+ // go trough the attribute data to see if anything matches
+ foreach($cycleData[2] as $cycleAttribute => $cycleValue)
+ {
+ if(in_array($cycleValue, $rowData[2]))
+ {
+ $rowData[3][$cycleAttribute] .= ' ' . $cycleData[3][$cycleAttribute];
+
+ // remove the data so we can use the others to merge the arrays
+ unset($cycleData[2][$cycleAttribute], $cycleData[3][$cycleAttribute]);
+ }
+ }
+
+ // merge all the values, so we get everything we need
+ $rowData[2] = array_merge($rowData[2], $cycleData[2]);
+ $rowData[3] = array_merge($rowData[3], $cycleData[3]);
+
+ // rebuild the data
+ $row['attributes'] = $this->getHTMLAttributes(array_combine($rowData[2], $rowData[3]));
+ }
+
+ // no match, just assign the cycle attributes as the row attributes
+ else $row['attributes'] = $cycleAttributes;
// define the columns
$columns = array();
@@ -1655,11 +1686,12 @@ public function setDebug($on = true)
*/
public function setEvenRowAttributes(array $attributes)
{
- // has results
if($this->source->getNumResults() > 0)
{
- // add to the list
- foreach($attributes as $key => $value) $this->attributes['row_even'][(string) $key] = (string) $value;
+ foreach($attributes as $key => $value)
+ {
+ $this->attributes['row_even'][(string) $key] = (string) $value;
+ }
}
}
@@ -1694,11 +1726,12 @@ public function setHeaderLabels(array $labels)
*/
public function setOddRowAttributes(array $attributes)
{
- // has results
if($this->source->getNumResults() > 0)
{
- // add to the list
- foreach($attributes as $key => $value) $this->attributes['row_odd'][(string) $key] = (string) $value;
+ foreach($attributes as $key => $value)
+ {
+ $this->attributes['row_odd'][(string) $key] = (string) $value;
+ }
}
}
View
2  spoon/datagrid/datagrid.tpl
@@ -35,7 +35,7 @@
</thead>
<tbody>
{iteration:rows}
- <tr{$rows.attributes}{$rows.oddAttributes}{$rows.evenAttributes}>
+ <tr{$rows.attributes}>
{iteration:rows.columns}<td{$rows.columns.attributes}>{$rows.columns.value}</td>{/iteration:rows.columns}
</tr>
{/iteration:rows}
View
16 spoon/directory/directory.php
@@ -36,14 +36,18 @@ class SpoonDirectory
* @param string $destination The full path to the destination.
* @param bool[optional] $overwrite If the destination already exists, should we overwrite?
* @param bool[optional] $strict If strict is true, exceptions will be thrown when an error occures.
- * @param int[optional] $chmod Mode that will be applied on the file/directory.
+ * @param int[optional] $chmod Chmod mode that should be applied on the directory/file. Defaults to 0777 (+rwx for all) for directories and 0666 (+rw for all) for files.
*/
- public static function copy($source, $destination, $overwrite = true, $strict = true, $chmod = 0777)
+ public static function copy($source, $destination, $overwrite = true, $strict = true, $chmod = null)
{
// redefine vars
$source = (string) $source;
$destination = (string) $destination;
$return = true;
+ if($chmod === null)
+ {
+ $chmod = is_dir($source) ? 0777 : 0666;
+ }
// validation
if($strict)
@@ -396,14 +400,18 @@ private static function isWritable($path)
* @param string $source Path of the source directory.
* @param string $destination Path of the destination.
* @param bool[optional] $overwrite Should an existing directory be overwritten?
- * @param int[optional] $chmod Mode that should be applied on the directory.
+ * @param int[optional] $chmod Chmod mode that should be applied on the directory/file. Defaults to 0777 (+rwx for all) for directories and 0666 (+rw for all) for files.
*/
- public static function move($source, $destination, $overwrite = true, $chmod = 0777)
+ public static function move($source, $destination, $overwrite = true, $chmod = null)
{
// redefine vars
$source = (string) $source;
$destination = (string) $destination;
$overwrite = (bool) $overwrite;
+ if($chmod === null)
+ {
+ $chmod = is_dir($source) ? 0777 : 0666;
+ }
// validation
if(!file_exists($source)) throw new SpoonDirectoryException('The given path (' . $source . ') doesn\'t exist.');
View
10 spoon/email/email.php
@@ -82,8 +82,8 @@ class SpoonEmail
* @var array
*/
private $content = array('html' => '', 'plain' => '');
-
-
+
+
/**
* Content transfer encoding value for the html and plaintext content.
*
@@ -663,6 +663,12 @@ private function reformatRecipientString(array $recipients)
// loop recipients
foreach($recipients as $recipient)
{
+ // name should NOT be an e-mail address
+ if(SpoonFilter::isEmail($recipient['name']))
+ {
+ throw new SpoonEmailException('E-mail addresses aren\'t allowed as names.');
+ }
+
// reformat to a proper string
$stack = $recipient['name'] . ' <' . $recipient['email'] . '>';
View
4 spoon/email/smtp.php
@@ -11,6 +11,7 @@
*
*
* @author Davy Hellemans <davy@spoon-library.com>
+ * @author Sam Tubbax <sam@sumocoders.be>
* @since 1.0.0
*/
@@ -352,6 +353,9 @@ public function send($data = null)
// code 354 means we can continue
if($this->repliedCode === 354)
{
+ // get rid of bare LFs
+ $data = str_replace("\n", "\r\n", $data);
+
// push our data
$this->say($data . self::CRLF . '.');
View
796 spoon/feed/atom_rss.php
@@ -0,0 +1,796 @@
+<?php
+
+/**
+ * Spoon Library
+ *
+ * This source file is part of the Spoon Library. More information,
+ * documentation and tutorials can be found @ http://www.spoon-library.com
+ *
+ * @package spoon
+ * @subpackage feed
+ *
+ * @author Davy Hellemans <davy@spoon-library.com>
+ * @since 1.1.0
+ */
+
+
+/**
+ * This base class provides all the methods used by Atom RSS-files
+ *
+ * @package spoon
+ * @subpackage feed
+ *
+ * @author Lowie Benoot <lowiebenoot@netlash.com>
+ * @since 1.1.0
+ */
+class SpoonFeedAtomRSS
+{
+ /**
+ * the authors (name, email, uri)
+ *
+ * @var array
+ */
+ private $authors = array();
+
+
+ /**
+ * Defines the categories the item belongs to
+ *
+ * @var array
+ */
+ private $categories = array();
+
+
+ /**
+ * The charset
+ *
+ * @var string
+ */
+ private $charset = 'utf-8';
+
+
+ /**
+ * the contributors (name, email, uri)
+ *
+ * @var array
+ */
+ private $contributors = array();
+
+
+ /**
+ * Generator
+ *
+ * @var string
+ */
+ private $generator;
+
+
+ /**
+ * Defines a small image which provides iconic visual identification for the feed.
+ *
+ * @var string
+ */
+ private $icon;
+
+
+ /**
+ * Defines the id for the item (=URI)
+ *
+ * @var string
+ */
+ private $id;
+
+
+ /**
+ * Items
+ *
+ * @var array
+ */
+ private $items = array();
+
+
+ /**
+ * Links
+ *
+ * @var array
+ */
+ private $links;
+
+
+ /**
+ * Defines a larger image which provides visual identification for the feed.
+ *
+ * @var string
+ */
+ private $logo;
+
+
+ /**
+ * Conveys information about rights, e.g. copyrights, held in and over the feed
+ *
+ * @var string
+ */
+ private $rights;
+
+
+ /**
+ * Subtitle
+ *
+ * @var string
+ */
+ private $subtitle;
+
+
+ /**
+ * Title
+ *
+ * @var string
+ */
+ private $title;
+
+
+ /**
+ * Defines the updated date for the feed
+ *
+ * @var int
+ */
+ private $updatedDate;
+
+
+ /**
+ * The default constructor
+ *
+ * @param string $title The title off the feed.
+ * @param string $id The id of the feed (URI).
+ * @param array[optional] $items An array with SpoonFeedRSSItems.
+ */
+ public function __construct($title, $id, array $items = array())
+ {
+ // set properties
+ $this->setTitle($title);
+ $this->setId($id);
+
+ // loop items and add them
+ foreach($items as $item) $this->addItem($item);
+ }
+
+
+ /**
+ * Add an author for the feed.
+ *
+ * @param array $author The author values (name, email, uri).
+ */
+ public function addAuthor($author)
+ {
+ $this->authors[] = $author;
+ }
+
+
+ /**
+ * Add a category for the feed.
+ *
+ * @param array $category The category with all the properties.
+ */
+ public function addCategory($category)
+ {
+ $this->categories[] = $category;
+ }
+
+
+ /**
+ * Add a contributor for the feed.
+ *
+ * @param string $name The name of the contributor.
+ * @param string $email The email of the contributor.
+ * @param string $uri The uri of the contributor.
+ */
+ public function addContributor($name, $email, $uri)
+ {
+ // create array
+ $contributor['name'] = (string) $name;
+ if($email != null) $contributor['email'] = (string) $email;
+ if($uri != null) $contributor['uri'] = (string) $uri;
+
+ // add property
+ $this->contributors[] = $contributor;
+ }
+
+
+ /**
+ * Add an item to the feed.
+ *
+ * @param SpoonFeedAtomRSSItem $item A SpoonFeedAtomRSSItem that represents a single article in the feed.
+ */
+ public function addItem(SpoonFeedAtomRSSItem $item)
+ {
+ $this->items[] = $item;
+ }
+
+
+ /**
+ * Add a link for the feed.
+ *
+ * @param array $link The link with all the properties.
+ */
+ public function addLink($link)
+ {
+ $this->links[] = $link;
+ }
+
+
+ /**
+ * Builds the XML.
+ *
+ * @return string The fully build XML for the feed.
+ */
+ public function buildXML()
+ {
+ // sort if needed
+ //if($this->getSorting()) $this->sort();
+
+ // init xml
+ $XML = '<?xml version="1.0" encoding="' . strtolower($this->getCharset()) . '" ?>' . "\n";
+ $XML .= '<feed xmlns="http://www.w3.org/2005/Atom">' . "\n";
+
+ // insert title
+ $XML .= ' <title>' . $this->getTitle() . '</title>' . "\n";
+
+ // insert subtitle
+ $subtitle = $this->getSubtitle();
+ if($subtitle != null) $XML .= ' <subtitle>' . $subtitle . '</subtitle>' . "\n";
+
+ // insert authors
+ $authors = $this->getAuthors();
+ if(!empty($authors))
+ {
+ foreach($authors as $author)
+ {
+ $XML .= ' <author>' . "\n";
+ $XML .= ' <name>' . $author['name'] . '</name>' . "\n";
+ if(isset($author['email'])) $XML .= ' <email>' . $author['email'] . '</email>' . "\n";
+ if(isset($author['uri'])) $XML .= ' <uri>' . $author['uri'] . '</uri>' . "\n";
+ $XML .= ' </author>' . "\n";
+ }
+ }
+
+ // insert contributors
+ $contributors = $this->getContributors();
+ if(!empty($contributors))
+ {
+ foreach($contributors as $contributor)
+ {
+ $XML .= ' <contributor>' . "\n";
+ $XML .= ' <name>' . $contributor['name'] . '</name>' . "\n";
+ if(isset($author['email'])) $XML .= ' <email>' . $contributor['email'] . '</email>' . "\n";
+ if(isset($author['uri'])) $XML .= ' <uri>' . $contributor['uri'] . '</uri>' . "\n";
+ $XML .= ' </contributor>' . "\n";
+ }
+ }
+
+ // insert id
+ $XML .= ' <id>' . $this->getId() . '</id>' . "\n";
+
+ // insert updated date
+ $updated = $this->getUpdatedDate();
+ if($updated != null) $XML .= ' <updated>' . date('Y-m-d\TH:i:s\Z', $updated) . '</updated>' . "\n";
+
+ // insert links
+ $links = $this->getLinks();
+ if(!empty($links))
+ {
+ foreach($links as $link)
+ {
+ $XML .= ' <link ';
+
+ // loop link attributes
+ foreach($link as $key => $value)
+ {
+ $XML .= $key . '="' . ($key == 'href' ? htmlentities($value) : $value) . '" ';
+ }
+
+ $XML .= '/>' . "\n";
+ }
+ }
+
+ // insert categories
+ $categories = $this->getCategories();
+ if(!empty($categories))
+ {
+ foreach($categories as $category)
+ {
+ $XML .= ' <category ';
+
+ // loop category attributes
+ foreach($category as $key => $value)
+ {
+ $XML .= $key . '="' . $value . '" ';
+ }
+
+ $XML .= '/>' . "\n";
+ }
+ }
+
+ // insert rights
+ $rights = $this->getRights();
+ if($rights != null) $XML .= ' <rights>' . $rights . '</rights>' . "\n";
+
+ // insert generator
+ $generator = $this->getGenerator();
+ if($generator != null) $XML .= ' <generator>' . $generator . '</generator>' . "\n";
+
+ // insert icon
+ $icon = $this->getIcon();
+ if($icon != null) $XML .= ' <icon>' . $icon . '</icon>' . "\n";
+
+ // insert logo
+ $logo = $this->getLogo();
+ if($logo != null) $XML .= ' <logo>' . $logo . '</logo>' . "\n";
+
+ // insert items
+ foreach($this->getItems() as $item)
+ {
+ $XML .= $item->parse();
+ }
+
+ // close feed
+ $XML .= '</feed>';
+
+ return $XML;
+ }
+
+
+ /**
+ * Get the authors.
+ *
+ * @return array An array with all authors.
+ */
+ public function getAuthors()
+ {
+ return $this->authors;
+ }
+
+
+ /**
+ * Get the categories.
+ *
+ * @return array An array with all categories.
+ */
+ public function getCategories()
+ {
+ return $this->categories;
+ }
+
+
+ /**
+ * Get the charset.
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->charset;
+ }
+
+
+ /**
+ * Get the contributors.
+ *
+ * @return array An array with all categories.
+ */
+ public function getContributors()
+ {
+ return $this->contributors;
+ }
+
+
+ /**
+ * Get the generator.
+ *
+ * @return string
+ */
+ public function getGenerator()
+ {
+ return $this->generator;
+ }
+
+
+ /**
+ * Get the icon for the feed.
+ *
+ * @return string
+ */
+ public function getIcon()
+ {
+ return $this->icon;
+ }
+
+
+ /**
+ * Get the id (URI).
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+
+ /**
+ * Retrieves the items.
+ *
+ * @return array
+ */
+ public function getItems()
+ {
+ return $this->items;
+ }
+
+
+ /**
+ * Get the links.
+ *
+ * @return array An array with all links.
+ */
+ public function getLinks()
+ {
+ return $this->links;
+ }
+
+
+ /**
+ * Get the logo for the feed.
+ *
+ * @return string
+ */
+ public function getLogo()
+ {
+ return $this->logo;
+ }
+
+
+ /**
+ * Get the rights for the feed.
+ *
+ * @return string
+ */
+ public function getRights()
+ {
+ return $this->rights;
+ }
+
+
+ /**
+ * Get the subtitle for the feed.
+ *
+ * @return string
+ */
+ public function getSubtitle()
+ {
+ return $this->subtitle;
+ }
+
+
+ /**
+ * Get the title for the feed.
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+
+ /**
+ * Get the updated date as a UNIX timestamp.
+ *
+ * @return int
+ */
+ public function getUpdatedDate()
+ {
+ return $this->updatedDate;
+ }
+
+
+ /**
+ * Checks if the feed is valid.
+ *
+ * @return bool
+ * @param string $URL An URL where the feed is located or the XML of the feed.
+ * @param string[optional] $type The type of feed, possible values are: url, string.
+ */
+ public static function isValid($URL, $type = 'url')
+ {
+ // redefine var
+ $URL = (string) $URL;
+ $type = (string) SpoonFilter::getValue($type, array('url', 'string'), 'url');
+
+ // validate
+ if($type == 'url' && !SpoonFilter::isURL($URL)) throw new SpoonFeedException('This (' . $URL . ') isn\'t a valid url.');
+
+ // load xmlstring
+ if($type == 'url')
+ {
+ // check if allow_url_fopen is enabled
+ if(ini_get('allow_url_fopen') == 0) throw new SpoonFeedException('allow_url_fopen should be enabled, if you want to get a remote URL.');
+
+ // open the url
+ $handle = @fopen($URL, 'r');
+
+ // validate the handle
+ if($handle === false) throw new SpoonFeedException('Something went wrong while retrieving the URL.');
+
+ // read the string
+ $xmlString = @stream_get_contents($handle);
+
+ // close the hanlde
+ @fclose($handle);
+ }
+
+ // not that url
+ else $xmlString = $URL;
+
+ // convert to simpleXML
+ $XML = @simplexml_load_string($xmlString);
+
+ // invalid XML?
+ if($XML === false) return false;
+
+ // check if all needed elements are present
+ if(!isset($XML->title) || !isset($XML->id) || !isset($XML->entry)) return false;
+
+ // loop items
+ foreach($XML->entry as $item)
+ {
+ // validate items
+ if(!SpoonFeedAtomRSSItem::isValid($item)) return false;
+ }
+
+ // fallback
+ return true;
+ }
+
+
+ /**
+ * Reads an feed into a SpoonRSS object.
+ *
+ * @return SpoonAtomRSS Returns as an instance of SpoonAtomRSS.
+ * @param string $URL An URL where the feed is located or the XML of the feed.
+ * @param string[optional] $type The type of feed, possible values are: url, string.
+ * @param bool[optional] $force Force to read this feed without validation.
+ */
+ public static function readFromFeed($URL, $type = 'url', $force = false)
+ {
+ // redefine var
+ $URL = (string) $URL;
+ $type = (string) SpoonFilter::getValue($type, array('url', 'string'), 'url');
+
+ // validate
+ if($type == 'url' && !SpoonFilter::isURL($URL)) throw new SpoonFeedException('This (' . SpoonFilter::htmlentities($URL) . ') isn\'t a valid URL.');
+ if(!$force) if(!self::isValid($URL, $type)) throw new SpoonFeedException('Invalid feed');
+
+ // load xmlstring
+ if($type == 'url') $xmlString = SpoonHTTP::getContent($URL);
+
+ // not that url
+ else $xmlString = $URL;
+
+ // convert to simpleXML
+ $XML = @simplexml_load_string($xmlString);
+
+ // validate the feed
+ if($XML === false) throw new SpoonFeedException('Invalid rss-string.');
+
+ // get title, link and description
+ $title = (string) $XML->title;
+ $id = (string) $XML->id;
+
+ // create instance
+ $RSS = new SpoonFeedAtomRSS($title, $id);
+
+ // add authors
+ if(isset($XML->author))
+ {
+ foreach($XML->author as $author)
+ {
+ // get the values
+ $author['name'] = (string) $XML->author->name;
+ $author['email'] = (isset($XML->author->email)) ? (string) $XML->author->email : null;
+ $author['uri'] = (isset($XML->author->uri)) ? (string) $XML->author->uri : null;
+
+ // set the values
+ $RSS->addAuthor($author);
+ }
+ }
+
+ // add contributors
+ if(isset($XML->contributor))
+ {
+ foreach($XML->contributor as $contributor)
+ {
+ $name = (string) $contributor['name'];
+ $email = isset($contributor['scheme']) ? (string) $contributor['email'] : null;
+ $uri = isset($contributor['label']) ? (string) $contributor['uri$contributor'] : null;
+
+ // set property
+ $RSS->addContributor($name, $email, $uri);
+ }
+ }
+
+ // add categories
+ if(isset($XML->category))
+ {
+ foreach($XML->category as $category)
+ {
+ // build category
+ $cat['term'] = (string) $category['term'];
+ if(isset($category['scheme'])) $cat['scheme'] = (string) $category['scheme'];
+ if(isset($category['label'])) $cat['label'] = (string) $category['label'];
+
+ // set property
+ $RSS->addCategory($cat);
+ }
+ }
+
+ // add links
+ if(isset($XML->link))
+ {
+ foreach($XML->link as $link)
+ {
+ // build link
+ $aLink['href'] = $link['href'];
+ if(isset($link['rel'])) $aLink['rel'] = $link['rel'];
+ if(isset($link['type'])) $aLink['type'] = $link['type'];
+ if(isset($link['title'])) $aLink['title'] = $link['title'];
+ if(isset($link['hreflang'])) $aLink['hreflang'] = $link['hreflang'];
+ if(isset($link['length'])) $aLink['length'] = $link['length'];
+
+ // set property
+ $RSS->addLink($aLink);
+ }
+ }
+
+ // add items
+ foreach($XML->entry as $item)
+ {
+ // try to read
+ try
+ {
+ // read xml
+ $item = SpoonFeedAtomRSSItem::readFromXML($item);
+ $RSS->addItem($item);
+ }
+
+ // catch exceptions
+ catch(Exception $e)
+ {
+ // ignore exceptions
+ }
+ }
+
+ // set updated date
+ if(isset($XML->updated)) $RSS->setUpdatedDate((int) strtotime($XML->updated));
+
+ // set generator
+ if(isset($XML->generator)) $RSS->setGenerator((string) $XML->generator);
+
+ // set icon
+ if(isset($XML->icon)) $RSS->setIcon((string) $XML->icon);
+
+ // set logo
+ if(isset($XML->logo)) $RSS->setLogo((string) $XML->logo);
+
+ // set rights
+ if(isset($XML->rights)) $RSS->setRights((string) $XML->rights);
+
+ // return
+ return $RSS;
+ }
+
+
+ /**
+ * Set the charset.
+ *
+ * @param string[optional] $charset The charset that should be used. Possible charsets can be found in spoon.php.
+ */
+ public function setCharset($charset = 'utf-8')
+ {
+ $this->charset = SpoonFilter::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET);
+ }
+
+
+ /**
+ * Set the generator for the feed.
+ *
+ * @param string[optional] $generator The generator of the feed, if not given "Spoon/<SpoonVersion>" will be used.
+ */
+ public function setGenerator($generator = null)
+ {
+ $this->generator = ($generator == null) ? 'Spoon/' . SPOON_VERSION : (string) $generator;
+ }
+
+
+ /**
+ * Set the icon for the feed.
+ *
+ * @param string $icon The url for the icon .
+ */
+ public function setIcon($icon)
+ {
+ $this->icon = (string) $icon;
+ }
+
+
+ /**
+ * Set the id (URI).
+ *
+ * @param string $id The id (URI) of the item (example: http://example.com/blog/1234).
+ */
+ public function setId($id)
+ {
+ // redefine var
+ $id = (string) $id;
+
+ // validate
+ if(!SpoonFilter::isURL($id)) throw new SpoonFeedException('This (' . $id . ') isn\'t a valid link.');
+
+ // set property
+ $this->id = $id;
+ }
+
+
+ /**
+ * Set the icon for the feed.
+ *
+ * @param string $logo The url for the logo .
+ */
+ public function setLogo($logo)
+ {
+ $this->logo = (string) $logo;
+ }
+
+
+ /**
+ * Set the rights for the feed.
+ *
+ * @param string $rights Conveys information about rights, e.g. copyrights, held in and over the feed.
+ */
+ public function setRights($rights)
+ {
+ $this->rights = (string) $rights;
+ }
+
+
+ /**
+ * Set the subtitle for the feed.
+ *
+ * @param string $subtitle The subtitle of the feed.
+ */
+ public function setSubtitle($subtitle)
+ {
+ $this->subtitle = (string) $subtitle;
+ }
+
+
+ /**
+ * Set the title for the feed.
+ *
+ * @param string $title The title of the feed.
+ */
+ public function setTitle($title)
+ {
+ $this->title = (string) $title;
+ }
+
+
+ /**
+ * Set the updated date.
+ *
+ * @param int $updatedDate The updated date as a UNIX-timestamp.
+ */
+ public function setUpdatedDate($updatedDate)
+ {
+ $this->updatedDate = (int) $updatedDate;
+ }
+}
View
638 spoon/feed/atom_rss_item.php
@@ -0,0 +1,638 @@
+<?php
+
+/**
+ * Spoon Library
+ *
+ * This source file is part of the Spoon Library. More information,
+ * documentation and tutorials can be found @ http://www.spoon-library.com
+ *
+ * @package spoon
+ * @subpackage feed
+ *
+ * @author Davy Hellemans <davy@spoon-library.com>
+ * @since 1.1.0
+ */
+
+
+/**
+ * This base class provides all the methods used by Atom RSS-items.
+ *
+ * @package spoon
+ * @subpackage feed
+ *
+ *
+ * @author Lowie Benoot <lowiebenoot@netlash.com>
+ * @since 1.1.0
+ */
+class SpoonFeedAtomRSSItem
+{
+ /**
+ * The authors (name, email, uri)
+ *
+ * @var array
+ */
+ private $authors = array();
+
+
+ /**
+ * Defines the categories the item belongs to
+ *
+ * @var array
+ */
+ private $categories = array();
+
+
+ /**
+ * Specifies the content of the item
+ *
+ * @var string
+ */
+ private $content;
+
+
+ /**
+ * the contributors (name, email, uri)
+ *
+ * @var array
+ */
+ private $contributors = array();
+
+
+ /**
+ * Defines the id for the item (=URI)
+ *
+ * @var string
+ */
+ private $id;
+
+
+ /**
+ * Links
+ *
+ * @var array
+ */
+ private $links;
+
+
+ /**
+ * Defines the last-publication date for the item
+ *
+ * @var int
+ */
+ private $publicationDate;
+
+
+ /**
+ * Conveys information about rights, e.g. copyrights, held in and over the item
+ *
+ * @var string
+ */
+ private $rights;
+
+
+ /**
+ * summary for the item
+ *
+ * @var string
+ */
+ private $summary;
+
+
+ /**
+ * Defines the title of the item
+ *
+ * @var string
+ */
+ private $title;
+
+
+ /**
+ * Defines the updated date for the feed
+ *
+ * @var int
+ */
+ private $updatedDate;
+
+
+ /**
+ * Default constructor.
+ *
+ * @param string $title The title for the item.
+ * @param string $id The id of the item (URI).
+ * @param string $summary The summary for the item.
+ */
+ public function __construct($title, $id, $summary)
+ {
+ // set properties
+ $this->setTitle($title);
+ $this->setId($id);
+ $this->setSummary($summary);
+ }
+
+
+ /**
+ * Add an author for the item.
+ *
+ * @param array $author The author values (name, email, uri).
+ */
+ public function addAuthor($author)
+ {
+ $this->authors[] = $author;
+ }
+
+
+ /**
+ * Add a category for the item.
+ *
+ * @param array $category The category with all the properties.
+ */
+ public function addCategory($category)
+ {
+ $this->categories[] = $category;
+ }
+
+
+ /**
+ * Add a contributor for the item.
+ *
+ * @param string $name The name of the contributor.
+ * @param string $email The email of the contributor.
+ * @param string $uri The uri of the contributor.
+ */
+ public function addContributor($name, $email, $uri)
+ {
+ // create array
+ $contributor['name'] = (string) $name;
+ if($email != null) $contributor['email'] = (string) $email;
+ if($uri != null) $contributor['uri'] = (string) $uri;
+
+ // add property
+ $this->contributors[] = $contributor;
+ }
+
+
+ /**
+ * Add a link for the item.
+ *
+ * @param array $link The link with all the properties.
+ */
+ public function addLink($link)
+ {
+ $this->links[] = $link;
+ }
+
+
+ /**
+ * Builds the XML.
+ *
+ * @return string The fully build XML for an item.
+ */
+ public function buildXML()
+ {
+ // init xmlstring
+ $XML = '<entry>' . "\n";
+
+ // insert title
+ $XML .= ' <title>' . $this->getTitle() . '</title>' . "\n";
+
+ // insert authors
+ $authors = $this->getAuthors();
+ if(!empty($authors))
+ {
+ foreach($authors as $author)
+ {
+ $XML .= ' <author>' . "\n";
+ $XML .= ' <name>' . $author['name'] . '</name>' . "\n";
+ if(isset($author['email'])) $XML .= ' <email>' . $author['email'] . '</email>' . "\n";
+ if(isset($author['uri'])) $XML .= ' <uri>' . $author['uri'] . '</uri>' . "\n";
+ $XML .= ' </author>' . "\n";
+ }
+ }
+
+ // insert contributors
+ $contributors = $this->getContributors();
+ if(!empty($contributors))
+ {
+ foreach($contributors as $contributor)
+ {
+ $XML .= ' <contributor>' . "\n";
+ $XML .= ' <name>' . $contributor['name'] . '</name>' . "\n";
+ if(isset($author['email'])) $XML .= ' <email>' . $contributor['email'] . '</email>' . "\n";
+ if(isset($author['uri'])) $XML .= ' <uri>' . $contributor['uri'] . '</uri>' . "\n";
+ $XML .= ' </contributor>' . "\n";
+ }
+ }
+
+ // insert id
+ $XML .= ' <id>' . $this->getId() . '</id>' . "\n";
+
+ // insert updated date
+ $updated = $this->getUpdatedDate();
+ if($updated != null) $XML .= ' <updated>' . date('Y-m-d\TH:i:s\Z', $updated) . '</updated>' . "\n";
+
+ // insert publication date
+ $published = $this->getPublicationDate();
+ if($published != null) $XML .= ' <published>' . date('Y-m-d\TH:i:s\Z', $published) . '</published>' . "\n";
+
+ // insert rights
+ $rights = $this->getRights();
+ if($rights != null) $XML .= ' <rights>' . $rights . '</rights>';
+
+ // insert links
+ $links = $this->getLinks();
+ if(!empty($links))
+ {
+ foreach($links as $link)
+ {
+ $XML .= ' <link ';
+
+ // loop link attributes
+ foreach($link as $key => $value)
+ {
+ $XML .= $key . '="' . ($key == 'href' ? htmlentities($value) : $value) . '" ';
+ }
+
+ $XML .= '/>' . "\n";
+ }
+ }
+
+ // insert categories
+ $categories = $this->getCategories();
+ if(!empty($categories))
+ {
+ foreach($categories as $category)
+ {
+ $XML .= ' <category ';
+
+ // loop category attributes
+ foreach($category as $key => $value)
+ {
+ $XML .= $key . '="' . $value . '" ';
+ }
+
+ $XML .= '/>' . "\n";
+ }
+ }
+
+ // insert summary
+ $XML .= ' <summary type="html">' . "\n";
+ $XML .= ' <![CDATA[' . "\n";
+ $XML .= ' ' . $this->getSummary() . "\n";
+ $XML .= ' ]]>' . "\n";
+ $XML .= ' </summary>' . "\n";
+
+ // insert content
+ $content = $this->getContent();
+ if($content != null)
+ {
+ $XML .= ' <content type="html">' . "\n";
+ $XML .= ' <![CDATA[' . "\n";
+ $XML .= ' ' . $content . "\n";
+ $XML .= ' ]]>' . "\n";
+ $XML .= ' </content>' . "\n";
+ }
+
+ // close item
+ $XML .= '</entry>' . "\n";
+
+ // return
+ return $XML;
+ }
+
+
+ /**
+ * Get the authors.
+ *
+ * @return array An array with all authors.
+ */
+ public function getAuthors()
+ {
+ return $this->authors;
+ }
+
+
+ /**
+ * Get the categories.
+ *
+ * @return array An array with all categories.
+ */
+ public function getCategories()
+ {
+ return $this->categories;
+ }
+
+
+ /**
+ * Get the content.
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+
+ /**
+ * Get the contributors.
+ *
+ * @return array An array with all categories.
+ */
+ public function getContributors()
+ {
+ return $this->contributors;
+ }
+
+
+ /**
+ * Get the id (URI).
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+
+ /**
+ * Get the links.
+ *
+ * @return array An array with all links.
+ */
+ public function getLinks()
+ {
+ return $this->links;
+ }
+
+
+ /**
+ * Get the publication date.
+ *
+ * @return int
+ */
+ public function getPublicationDate()
+ {
+ return $this->publicationDate;
+ }
+
+
+ /**
+ * Get the rights for the feed.
+ *
+ * @return string
+ */
+ public function getRights()
+ {
+ return $this->rights;
+ }
+
+
+ /**
+ * Get the summary.
+ *
+ * @return string
+ */
+ public function getSummary()
+ {
+ return $this->summary;
+ }
+
+
+ /**
+ * Get the title.
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+
+ /**
+ * Get the updated date as a UNIX timestamp.
+ *
+ * @return int
+ */
+ public function getUpdatedDate()
+ {
+ return $this->updatedDate;
+ }
+
+
+ /**
+ * Validate if the given XML is valid.
+ *
+ * @return bool True if the item is valid, otherwise false.
+ * @param SimpleXMLElement $item An item/article from the whole feed.
+ */
+ public static function isValid(SimpleXMLElement $item)
+ {
+ // are all needed elements present?
+ if(!isset($item->title) || !isset($item->id) || !isset($item->summary)) return false;
+
+ // fallback
+ return true;
+ }
+
+
+ /**
+ * Parse the item
+ *
+ * @return string The XML for the item.
+ */
+ public function parse()
+ {
+ return $this->buildXML();
+ }
+
+
+ /**
+ * Read an item from a SimpleXMLElement.
+ *
+ * @return SpoonAtomRSSItem An instance of SpoonAtomRSSItem
+ * @param SimpleXMLElement $item The XML-element that represents a single item in the feed.
+ */
+ public static function readFromXML(SimpleXMLElement $item)
+ {
+ // get title, id and summary
+ $title = (string) $item->title;
+ $id = (string) $item->id;
+ $summary = (string) $item->summary;
+
+ // create instance
+ $rssItem = new SpoonFeedAtomRSSItem($title, $id, $summary);
+
+ // set updated date
+ if(isset($item->updated)) $rssItem->setUpdatedDate((int) strtotime($item->updated));
+
+ // add authors
+ if(isset($item->author))
+ {
+ foreach($item->author as $author)
+ {
+ // get the values
+ $author['name'] = (string) $item->author->name;
+ if(isset($item->author->email)) $author['email'] = (string) $item->author->email;
+ if(isset($item->author->uri)) $author['uri'] = (string) $item->author->uri;
+
+ // set the values
+ $rssItem->addAuthor($author);
+ }
+ }
+
+ // set content
+ if(isset($item->content)) $rssItem->setContent((string) $item->content);
+
+ // add links
+ if(isset($item->link))
+ {
+ foreach($item->link as $link)
+ {
+ // build link
+ $aLink['href'] = $link['href'];
+ if(isset($link['rel'])) $aLink['rel'] = $link['rel'];
+ if(isset($link['type'])) $aLink['type'] = $link['type'];
+ if(isset($link['title'])) $aLink['title'] = $link['title'];
+ if(isset($link['hreflang'])) $aLink['hreflang'] = $link['hreflang'];
+ if(isset($link['length'])) $aLink['length'] = $link['length'];
+
+ // set property
+ $rssItem->addLink($aLink);
+ }
+ }
+
+ // add categories
+ if(isset($item->category))
+ {
+ foreach($item->category as $category)
+ {
+ // build category
+ $cat['term'] = (string) $category['term'];
+ if(isset($category['scheme'])) $cat['scheme'] = (string) $category['scheme'];
+ if(isset($category['label'])) $cat['label'] = (string) $category['label'];
+
+ // set property
+ $rssItem->addCategory($cat);
+ }
+ }
+
+ // add contributors
+ if(isset($item->contributor))
+ {
+ foreach($item->contributor as $contributor)
+ {
+ $name = (string) $contributor['name'];
+ $email = isset($contributor['scheme']) ? (string) $contributor['email'] : null;
+ $uri = isset($contributor['label']) ? (string) $contributor['uri$contributor'] : null;
+
+ // set property
+ $rssItem->addContributor($name, $email, $uri);
+ }
+ }
+
+ // set publication date
+ if(isset($item->published)) $rssItem->setPublicationDate((int) strtotime($item->published));
+
+ // set rights
+ if(isset($XML->rights)) $rssItem->setRights((string) $XML->rights);
+
+ return $rssItem;
+ }
+
+
+ /**
+ * Set the author.
+ *
+ * @param string $author The author of the item.
+ */
+ public function setAuthor($author)
+ {
+ $this->author = (string) $author;
+ }
+
+
+ /**
+ * Set the content.
+ *
+ * @param string $content The content of the item.
+ */
+ public function setContent($content)
+ {
+ $this->content = (string) $content;
+ }
+
+
+ /**
+ * Set the id (URI).
+ *
+ * @param string $id The id (URI) of the item (example: http://example.com/blog/1234).
+ */
+ public function setId($id)
+ {
+ // redefine var
+ $id = (string) $id;
+
+ // validate
+ if(!SpoonFilter::isURL($id)) throw new SpoonFeedException('This (' . $id . ') isn\'t a valid link.');
+
+ // set property
+ $this->id = $id;
+ }
+
+
+ /**
+ * Set the publication date.
+ *
+ * @param int $publicationDate The publication date as a UNIX-timestamp.
+ */
+ public function setPublicationDate($publicationDate)
+ {
+ $this->publicationDate = (int) $publicationDate;
+ }
+
+
+ /**
+ * Set the rights for the item.
+ *
+ * @param string $rights Conveys information about rights, e.g. copyrights, held in and over the item.
+ */
+ public function setRights($rights)
+ {
+ $this->rights = (string) $rights;
+ }
+
+
+ /**
+ * Set the summary.
+ *
+ * @param string $summary The content of the item.
+ */
+ public function setSummary($summary)
+ {
+ $this->summary = (string) $summary;
+ }
+
+
+ /**
+ * Set the title.
+ *
+ * @param string $title The title of the item.
+ */
+ public function setTitle($title)
+ {
+ $this->title = (string) $title;
+ }
+
+
+ /**
+ * Set the updated date.
+ *
+ * @param int $updatedDate The updated date as a UNIX-timestamp.
+ */
+ public function setUpdatedDate($updatedDate)
+ {
+ $this->updatedDate = (int) $updatedDate;
+ }
+}
View
8 spoon/feed/rss.php
@@ -279,7 +279,7 @@ public function addSkipDay($day)
if(in_array($day, $this->skipDays)) throw new SpoonFeedException('This (' . $day . ') day was already added.');
// set property
- $this->skipDays[] = ucfirst($day);
+ $this->skipDays[] = SpoonFilter::ucfirst($day);
}
@@ -837,8 +837,9 @@ public function parseToFile($path)
* @return SpoonRSS Returns as an instance of SpoonRSS.
* @param string $URL An URL where the feed is located or the XML of the feed.
* @param string[optional] $type The type of feed, possible values are: url, string.
+ * @param bool[optional] $force Force to read this feed without validation.
*/
- public static function readFromFeed($URL, $type = 'url')
+ public static function readFromFeed($URL, $type = 'url', $force = false)
{
// redefine var
$URL = (string) $URL;
@@ -846,7 +847,7 @@ public static function readFromFeed($URL, $type = 'url')
// validate
if($type == 'url' && !SpoonFilter::isURL($URL)) throw new SpoonFeedException('This (' . SpoonFilter::htmlentities($URL) . ') isn\'t a valid URL.');
- if(!self::isValid($URL, $type)) throw new SpoonFeedException('Invalid feed');
+ if(!$force) if(!self::isValid($URL, $type)) throw new SpoonFeedException('Invalid feed');
// load xmlstring
if($type == 'url') $xmlString = SpoonHTTP::getContent($URL);
@@ -1294,7 +1295,6 @@ public function setWebmaster($webmaster)
/**
* Sort the item on publication date.
- *
*/
private function sort()
{
View
8 spoon/file/csv.php
@@ -66,8 +66,9 @@ public static function arrayToFile($path, array $array, array $columns = null, a
* @param array[optional] $excludeColumns The columns you want to exclude.
* @param string[optional] $delimiter The field delimiter of the CSV.
* @param string[optional] $enclosure The enclosure character of the CSV.
+ * @param string[optional] $lineEnding The line-ending of the CSV.
*/
- public static function arrayToString(array $array, array $columns = null, array $excludeColumns = null, $delimiter = ',', $enclosure = '"')
+ public static function arrayToString(array $array, array $columns = null, array $excludeColumns = null, $delimiter = ',', $enclosure = '"', $lineEnding = null)
{
// validate array
if(!empty($array) && !isset($array[0])) throw new SpoonFileException('Invalid array format.');
@@ -81,6 +82,7 @@ public static function arrayToString(array $array, array $columns = null, array
// check for delimiter/enclosure
if($delimiter === null) $delimiter = self::DEFAULT_DELIMITER;
if($enclosure === null) $enclosure = self::DEFAULT_ENCLOSURE;
+ if($lineEnding === null) $lineEnding = PHP_EOL;
// unset the excluded columns
if(!empty($excludeColumns)) foreach($excludeColumns as $column) unset($columns[array_search($column, $columns)]);
@@ -89,7 +91,7 @@ public static function arrayToString(array $array, array $columns = null, array
$columns = self::escapeEnclosure($columns, $enclosure);
// start the string with the columns
- $csv = $enclosure . implode($enclosure . $delimiter . $enclosure, $columns) . $enclosure . PHP_EOL;
+ $csv = $enclosure . implode($enclosure . $delimiter . $enclosure, $columns) . $enclosure . $lineEnding;
// stop here if the array is empty
if(empty($array)) return $csv;
@@ -114,7 +116,7 @@ public static function arrayToString(array $array, array $columns = null, array
$row = self::escapeEnclosure($row, $enclosure);
// add this row to the CSV
- $csv .= $enclosure . implode($enclosure . $delimiter . $enclosure, (array) $row) . $enclosure . PHP_EOL;
+ $csv .= $enclosure . implode($enclosure . $delimiter . $enclosure, (array) $row) . $enclosure . $lineEnding;
}
// no input
View
13 spoon/file/file.php
@@ -281,10 +281,15 @@ public static function getList($path, $includeRegexp = null)
* @param string $source Path of the source file.
* @param string $destination Path of the destination.
* @param bool[optional] $overwrite Should an existing file be overwritten?
- * @param int[optional] $chmod Chmod mode that should be applied on the file/directory.
+ * @param int[optional] $chmod Chmod mode that should be applied on the file/directory. Defaults to 0777 (+rwx for all) for directories and 0666 (+rw for all) for files.
*/
- public static function move($source, $destination, $overwrite = true, $chmod = 0777)
+ public static function move($source, $destination, $overwrite = true, $chmod = null)
{
+ if($chmod === null)
+ {
+ $chmod = is_dir($source) ? 0777 : 0666;
+ }
+
return SpoonDirectory::move($source, $destination, $overwrite, $chmod);
}
@@ -299,7 +304,7 @@ public static function move($source, $destination, $overwrite = true, $chmod = 0
* @param bool[optional] $append Should the content be appended if the file already exists?
* @param int[optional] $chmod Mode that should be applied on the file.
*/
- public static function setContent($filename, $content, $createFile = true, $append = false, $chmod = 0777)
+ public static function setContent($filename, $content, $createFile = true, $append = false, $chmod = 0666)
{
// redefine vars
$filename = (string) $filename;
@@ -311,7 +316,7 @@ public static function setContent($filename, $content, $createFile = true, $appe
if(!$createFile && self::exists($filename)) throw new SpoonFileException('The file "' . $filename . '" doesn\'t exist');
// create directory recursively if needed
- SpoonDirectory::create(dirname($filename), $chmod, true);
+ SpoonDirectory::create(dirname($filename));
// create file & open for writing
$handler = ($append) ? @fopen($filename, 'a') : @fopen($filename, 'w');
View
148 spoon/filter/filter.php
@@ -139,8 +139,6 @@ public static function arraySortKeys(array $array)
/**
* Disable php's magic quotes (yuck!)
- *
- * @return void
*/
public static function disableMagicQuotes()
{
@@ -308,8 +306,8 @@ public static function htmlentities($value, $charset = null, $quoteStyle = ENT_N
$charset = ($charset !== null) ? self::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET) : SPOON_CHARSET;
$quoteStyle = self::getValue($quoteStyle, array(ENT_COMPAT, ENT_QUOTES, ENT_NOQUOTES), ENT_NOQUOTES);
- // apply method
- $return = htmlentities($value, $quoteStyle, $charset);
+ // apply htmlentities
+ $return = htmlentities((string) $value, $quoteStyle, $charset);
/**
* PHP doesn't replace a backslash to its html entity since this is something
@@ -336,7 +334,7 @@ public static function htmlentitiesDecode($value, $charset = null, $quoteStyle =
$quoteStyle = self::getValue($quoteStyle, array(ENT_COMPAT, ENT_QUOTES, ENT_NOQUOTES), ENT_NOQUOTES);
// apply method
- return html_entity_decode($value, $quoteStyle, $charset);
+ return html_entity_decode((string) $value, $quoteStyle, $charset);
}
@@ -353,7 +351,7 @@ public static function htmlspecialchars($value, $charset = null)
$charset = ($charset !== null) ? self::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET) : SPOON_CHARSET;
// apply method
- return htmlspecialchars($value, ENT_QUOTES, $charset);
+ return htmlspecialchars((string) $value, ENT_QUOTES, $charset);
}
@@ -365,7 +363,7 @@ public static function htmlspecialchars($value, $charset = null)
*/
public static function htmlspecialcharsDecode($value)
{
- return htmlspecialchars_decode($value, ENT_QUOTES);
+ return htmlspecialchars_decode((string) $value, ENT_QUOTES);
}
@@ -476,18 +474,21 @@ public static function isFilename($value)
*/
public static function isFloat($value, $allowCommas = false)
{
- // no commas allowed
- if(!$allowCommas) return ((string) (float) $value === (string) $value);
+ // replace commas if needed
+ if($allowCommas) $value = str_replace(',', '.', (string) $value);
- // replace commas with dots
- return ((string) (float) str_replace(',', '.', (string) $value) === str_replace(',', '.', (string) $value));
+ // trim zero characters after the decimal separator
+ if(mb_strpos((string) $value, '.') !== false) rtrim($value, '0');
+
+ // validate
+ return ((string) (float) $value === (string) $value);
}
/**
* Checks if the value is greather than a given minimum.
*
- * @return bool true if the value is greather then, false if not.
+ * @return bool true if the value is greather then, false if not.
* @param float $minimum The minimum as a float.
* @param float $value The value to validate.
*/
@@ -635,6 +636,32 @@ public static function isOdd($value)
/**
+ * Checks this field for numbers 0-9 and an optional - (minus) sign (in the beginning only).
+ *
+ * @return bool
+ * @param string $value The value to validate.
+ * @param string[optional] $error The error message to set.
+ * @param int[optional] $precision The allowed number of digits after the decimal separator. Defaults to 2.
+ * @param bool[optional] $allowNegative Do you want to allow negative prices? Defaults to false.
+ * @param bool[optional] $allowCommas Do you want to use commas as a decimal separator? Defaults to true.
+ */
+ public static function isPrice($value, $precision = 2, $allowNegative = false, $allowCommas = true)
+ {
+ // replace commas if needed
+ if($allowCommas) $value = str_replace(',', '.', (string) $value);
+
+ // trim zero characters after the decimal separator
+ if(mb_strpos($value, '.') !== false) rtrim($value, '0');
+
+ // no negatives allowed
+ if(!$allowNegative) return (((float) $value >= 0) && ((string) (float) $value == $value));
+
+ // no commas allowed
+ return ((string) (float) $value === (string) $value);
+ }
+
+
+ /**
* Checks if the value is smaller than a given maximum.
*
* @return bool True if the value is smaller, false if not.
@@ -836,10 +863,8 @@ public static function stripHTML($string, $exceptions = null, $replaceAnchorsWit
*/
public static function toCamelCase($value, $separator = '_', $lcfirst = false, $charset = null)
{
- $charset = ($charset !== null) ? self::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET) : SPOON_CHARSET;
-
- // init var
$string = '';
+ $charset = ($charset !== null) ? self::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET) : SPOON_CHARSET;
// fetch words
$words = explode((string) $separator, (string) $value);
@@ -851,7 +876,7 @@ public static function toCamelCase($value, $separator = '_', $lcfirst = false, $
if($word == '') continue;
// first word lowercase
- if($i == 0 && $lcfirst) $word = $word;
+ if($i == 0 && $lcfirst) $word[0] = mb_strtolower($word[0], $charset);
// convert first letter to uppercase
else $word[0] = mb_strtoupper($word[0], $charset);
@@ -864,68 +889,71 @@ public static function toCamelCase($value, $separator = '_', $lcfirst = false, $
/**
- * Prepares a string so that it can be used in urls. Special characters are stripped/replaced.
+ * Multibyte-safe ucfirst
*
- * @return string The urlised string.
- * @param string $value The value that should be urlised.
- * @param string[optional] $charset The charset to use, default is based on SPOON_CHARSET.
+ * @return string The ucfirst'ed string.
+ * @param string $string The string to ucfirst
+ * @param string[optional] $charset The charset to use, default is based on SPOON_CHARSET.
*/
- public static function urlise($value, $charset = null)
+ public static function ucfirst($string, $charset = null)
{
- // define charset
+ // init vars
$charset = ($charset !== null) ? self::getValue($charset, Spoon::getCharsets(), SPOON_CHARSET) : SPOON_CHARSET;
+ $string = (string) $string</