/Zend/Validate/Isbn.php

https://github.com/ftaiolivista/Zend-Framework-Namespaced- · PHP · 284 lines · 140 code · 29 blank · 115 comment · 36 complexity · b3c4483929d929c42f9db47b77693b09 MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Validate
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Isbn.php 22668 2010-07-25 14:50:46Z thomas $
  20. */
  21. /**
  22. * @namespace
  23. */
  24. namespace Zend\Validate;
  25. /**
  26. * @see Zend_Validate_Abstract
  27. */
  28. require_once 'Zend/Validate/Abstract.php';
  29. /**
  30. * @category Zend
  31. * @package Zend_Validate
  32. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. */
  35. class Isbn extends AbstractValidate
  36. {
  37. const AUTO = 'auto';
  38. const ISBN10 = '10';
  39. const ISBN13 = '13';
  40. const INVALID = 'isbnInvalid';
  41. const NO_ISBN = 'isbnNoIsbn';
  42. /**
  43. * Validation failure message template definitions.
  44. *
  45. * @var array
  46. */
  47. protected $_messageTemplates = array(
  48. self::INVALID => "Invalid type given. String or integer expected",
  49. self::NO_ISBN => "'%value%' is no valid ISBN number",
  50. );
  51. /**
  52. * Allowed type.
  53. *
  54. * @var string
  55. */
  56. protected $_type = self::AUTO;
  57. /**
  58. * Separator character.
  59. *
  60. * @var string
  61. */
  62. protected $_separator = '';
  63. /**
  64. * Set up options.
  65. *
  66. * @param Zend_Config|array $options
  67. * @throws Zend_Validate_Exception When $options is not valid
  68. * @return void
  69. */
  70. public function __construct($options = array())
  71. {
  72. // prepare options
  73. if ($options instanceof \Zend\Config\Config) {
  74. $options = $options->toArray();
  75. }
  76. if (!is_array($options)) {
  77. /**
  78. * @see Zend_Validate_Exception
  79. */
  80. require_once 'Zend/Validate/Exception.php';
  81. throw new Exception('Invalid options provided.');
  82. }
  83. // set type
  84. if (array_key_exists('type', $options)) {
  85. $this->setType($options['type']);
  86. }
  87. // set separator
  88. if (array_key_exists('separator', $options)) {
  89. $this->setSeparator($options['separator']);
  90. }
  91. }
  92. /**
  93. * Detect input format.
  94. *
  95. * @return string
  96. */
  97. protected function _detectFormat()
  98. {
  99. // prepare separator and pattern list
  100. $sep = quotemeta($this->_separator);
  101. $patterns = array();
  102. $lengths = array();
  103. // check for ISBN-10
  104. if ($this->_type == self::ISBN10 || $this->_type == self::AUTO) {
  105. if (empty($sep)) {
  106. $pattern = '/^[0-9]{9}[0-9X]{1}$/';
  107. $length = 10;
  108. } else {
  109. $pattern = "/^[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9X]{1}$/";
  110. $length = 13;
  111. }
  112. $patterns[$pattern] = self::ISBN10;
  113. $lengths[$pattern] = $length;
  114. }
  115. // check for ISBN-13
  116. if ($this->_type == self::ISBN13 || $this->_type == self::AUTO) {
  117. if (empty($sep)) {
  118. $pattern = '/^[0-9]{13}$/';
  119. $length = 13;
  120. } else {
  121. $pattern = "/^[0-9]{1,9}[{$sep}]{1}[0-9]{1,5}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1}$/";
  122. $length = 17;
  123. }
  124. $patterns[$pattern] = self::ISBN13;
  125. $lengths[$pattern] = $length;
  126. }
  127. // check pattern list
  128. foreach ($patterns as $pattern => $type) {
  129. if ((strlen($this->_value) == $lengths[$pattern]) && preg_match($pattern, $this->_value)) {
  130. return $type;
  131. }
  132. }
  133. return null;
  134. }
  135. /**
  136. * Defined by Zend_Validate_Interface.
  137. *
  138. * Returns true if and only if $value is a valid ISBN.
  139. *
  140. * @param string $value
  141. * @return boolean
  142. */
  143. public function isValid($value)
  144. {
  145. if (!is_string($value) && !is_int($value)) {
  146. $this->_error(self::INVALID);
  147. return false;
  148. }
  149. $value = (string) $value;
  150. $this->_setValue($value);
  151. switch ($this->_detectFormat()) {
  152. case self::ISBN10:
  153. // sum
  154. $isbn10 = str_replace($this->_separator, '', $value);
  155. $sum = 0;
  156. for ($i = 0; $i < 9; $i++) {
  157. $sum += (10 - $i) * $isbn10{$i};
  158. }
  159. // checksum
  160. $checksum = 11 - ($sum % 11);
  161. if ($checksum == 11) {
  162. $checksum = '0';
  163. } elseif ($checksum == 10) {
  164. $checksum = 'X';
  165. }
  166. break;
  167. case self::ISBN13:
  168. // sum
  169. $isbn13 = str_replace($this->_separator, '', $value);
  170. $sum = 0;
  171. for ($i = 0; $i < 12; $i++) {
  172. if ($i % 2 == 0) {
  173. $sum += $isbn13{$i};
  174. } else {
  175. $sum += 3 * $isbn13{$i};
  176. }
  177. }
  178. // checksum
  179. $checksum = 10 - ($sum % 10);
  180. if ($checksum == 10) {
  181. $checksum = '0';
  182. }
  183. break;
  184. default:
  185. $this->_error(self::NO_ISBN);
  186. return false;
  187. }
  188. // validate
  189. if (substr($this->_value, -1) != $checksum) {
  190. $this->_error(self::NO_ISBN);
  191. return false;
  192. }
  193. return true;
  194. }
  195. /**
  196. * Set separator characters.
  197. *
  198. * It is allowed only empty string, hyphen and space.
  199. *
  200. * @param string $separator
  201. * @throws Zend_Validate_Exception When $separator is not valid
  202. * @return Zend_Validate_Isbn Provides a fluent interface
  203. */
  204. public function setSeparator($separator)
  205. {
  206. // check separator
  207. if (!in_array($separator, array('-', ' ', ''))) {
  208. /**
  209. * @see Zend_Validate_Exception
  210. */
  211. require_once 'Zend/Validate/Exception.php';
  212. throw new Exception('Invalid ISBN separator.');
  213. }
  214. $this->_separator = $separator;
  215. return $this;
  216. }
  217. /**
  218. * Get separator characters.
  219. *
  220. * @return string
  221. */
  222. public function getSeparator()
  223. {
  224. return $this->_separator;
  225. }
  226. /**
  227. * Set allowed ISBN type.
  228. *
  229. * @param string $type
  230. * @throws Zend_Validate_Exception When $type is not valid
  231. * @return Zend_Validate_Isbn Provides a fluent interface
  232. */
  233. public function setType($type)
  234. {
  235. // check type
  236. if (!in_array($type, array(self::AUTO, self::ISBN10, self::ISBN13))) {
  237. /**
  238. * @see Zend_Validate_Exception
  239. */
  240. require_once 'Zend/Validate/Exception.php';
  241. throw new Exception('Invalid ISBN type');
  242. }
  243. $this->_type = $type;
  244. return $this;
  245. }
  246. /**
  247. * Get allowed ISBN type.
  248. *
  249. * @return string
  250. */
  251. public function getType()
  252. {
  253. return $this->_type;
  254. }
  255. }