Isbn.php 7.0 KB

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