ISBN
[ class tree: ISBN ] [ index: ISBN ] [ all elements ]

Source for file ISBN.php

Documentation is available at ISBN.php

  1. <?php
  2. /**
  3.  * ISBN
  4.  *
  5.  * Handle, Convert and Validate ISBN Numbers
  6.  *
  7.  * PHP version 5
  8.  *
  9.  * LICENSE: LGPL (In cases LGPL is not appropriate, it is licensed under GPL )
  10.  *
  11.  * Package to handle, convert and validate ISBN numbers. It includes:
  12.  *
  13.  *  - ISBN specifics: EAN/PrefixArrayAccess (integer)
  14.  *  - ISBN specifics: Group/Registration Group [2001: Group identifier] (integer)
  15.  *  - ISBN specifics: GroupTitle/Registration Group Title (string)
  16.  *  - ISBN specifics: Publisher/Registrant [2001: Publisher identifier] (string)
  17.  *  - ISBN specifics: Title/Publication [2001: Title identifier] (string)
  18.  *  - ISBN specifics: Checkdigit (string)
  19.  *  - ISBN specifics: 'ISBNBody' (string)
  20.  *  - ISBN specifics: 'ISBNSubbody' (string)
  21.  *  - ISBN Version handling
  22.  *  - Syntactical Validation plus Validation based on real ISBN Data
  23.  *  - ISBN-10 (ISO 2108) checksum calculation
  24.  *  - Validation (ISBN-10 and ISBN-13-978)
  25.  *  - Conversion to ISBN-13-978
  26.  *  - ISBN-13-978 (2005 Handbook, ISO pending; ISBN-13)
  27.  *  - ISBN-13 checksum calculation (EAN)
  28.  *
  29.  * Based on standards published by international ISBN Agency
  30.  * http://www.isbn-international.org/
  31.  *
  32.  * @category  pending
  33.  * @package   ISBN
  34.  * @author    Tom Klingenberg <tkli-php@lastflood.net>
  35.  * @copyright 2006-2007 Tom Klingenberg
  36.  * @license   LGPL http://www.gnu.org/licenses/lgpl.txt
  37.  * @version   v 0.1.4 CVS: <cvs_id>
  38.  * @link      http://isbn.lastflood.com online docs
  39.  * 
  40.  * @todo      License for .js file
  41.  * @todo      GroupTitle
  42.  * @todo      Re-Format1
  43.  *
  44.  */
  45.  
  46. // {{{ constants
  47. /**
  48.  * ISBN Versions supported
  49.  */
  50. define('ISBN_VERSION_NONE'false);
  51. /**
  52.  * VERSION_UNKNOWN is by the caller only, this shall never
  53.  * be a value returned by a public function or getter
  54.  */
  55. define('ISBN_VERSION_UNKNOWN'0);
  56. define('ISBN_VERSION_ISBN_10'10);
  57. define('ISBN_VERSION_ISBN_13'13978);
  58. define('ISBN_VERSION_ISBN_13_978'ISBN_VERSION_ISBN_13);
  59. define('ISBN_VERSION_ISBN_13_979'13979);  /* reserved */
  60.  
  61. /*
  62.  * Default ISBN Version for class input / usage
  63.  */
  64. define('ISBN_DEFAULT_INPUTVERSION'ISBN_VERSION_UNKNOWN);
  65. /*
  66.  * Default ISBN Seperator string
  67.  */
  68. define('ISBN_DEFAULT_COSMETIC_SEPERATOR''-');
  69.  
  70. /*
  71.  * ISBN_DEFAULT_PRINT_LANG_SPECIFIC_PREFIX
  72.  *
  73.  * When printed, the ISBN is always preceded by the letters "ISBN".
  74.  * Note: In countries where the Latin alphabet is not used, an abbreviation
  75.  * in the characters of the local script may be used in addition to the
  76.  * Latin letters "ISBN".
  77.  * This can be defined as a default value wihtin this constant.
  78.  */
  79. define('ISBN_DEFAULT_PRINT_LANG_SPECIFIC_PREFIX''');
  80. // }}}
  81.  
  82. require_once 'PEAR/Exception.php';
  83.  
  84. // {{{ ISBN_Exception
  85. /**
  86.  * ISBN_Exception class
  87.  *
  88.  * @category  pending
  89.  * @package   ISBN
  90.  * @author    Tom Klingenberg <tkli-php@lastflood.net>
  91.  * @copyright 2006-2007 Tom Klingenberg
  92.  * @license   LGPL http://www.gnu.org/licenses/lgpl.txt
  93.  * @link      http://isbn.lastflood.com/
  94.  * @since     Class available since Release 0.1.3
  95.  */
  96. class ISBN_Exception Extends PEAR_Exception
  97. {
  98. }
  99. // }}}
  100.  
  101. // {{{ ISBN
  102. /**
  103.  * ISBN class
  104.  *
  105.  * Class to Handle, Convert and Validate ISBN Numbers
  106.  *
  107.  * @category  pending
  108.  * @package   ISBN
  109.  * @author    Tom Klingenberg <tkli-php@lastflood.net>
  110.  * @copyright 2006-2007 Tom Klingenberg
  111.  * @license   LGPL http://www.gnu.org/licenses/lgpl.txt
  112.  * @link      http://isbn.lastflood.com/
  113.  * @since     Class available since Release 0.0.0
  114.  */
  115. class ISBN
  116. {
  117.     /**
  118.      * @var string ISBN Registration Group
  119.      */
  120.     private $isbn_group '';
  121.     /**
  122.      * @var string ISBN Publisher
  123.      */
  124.     private $isbn_publisher '';
  125.     /**
  126.      * @var string ISBN Title
  127.      */
  128.     private $isbn_title '';
  129.  
  130.     /**
  131.      * @var mixed ISBN number version
  132.      */
  133.     private $ver ISBN_VERSION_NONE;
  134.  
  135.     // {{{ __construct
  136.         /**
  137.      * Constructor
  138.      *
  139.      * @param array $isbn String of ISBN Value to use
  140.      * @param mixed $ver  Optional Version Constant
  141.      *
  142.      * @access public
  143.      * 
  144.      * @throws ISBN_Exception in case it fails
  145.      */
  146.     function __construct($isbn ''$ver ISBN_DEFAULT_INPUTVERSION)
  147.     {
  148.         /* validate & handle optional isbn parameter */
  149.         if (is_string($isbn== false {
  150.             throw new ISBN_Exception('ISBN parameter must be a string');
  151.         }
  152.         if (strlen($isbn== 0{
  153.             $this->setISBN($isbn);
  154.             return;
  155.         }
  156.  
  157.         /* validate version parameter */
  158.         if (self::_isbnVersionIs($ver== false{
  159.             throw new ISBN_Exception(
  160.                 'ISBN Version parameter is not an ISBN Version'
  161.             );
  162.         }
  163.  
  164.         /* ISBN has been passed, check the version now:
  165.          *     if it is unknown, try to dertine it, if this fails
  166.          *     throw an exception
  167.          */
  168.         if ($ver == ISBN_VERSION_UNKNOWN{
  169.             $verguess self::_isbnVersionGuess($isbn);
  170.             if (self::_isbnVersionIsValid($verguess)) {
  171.                 $ver $verguess;
  172.             else {
  173.                 /* throw new ISBN_Exception(
  174.                  *'ISBN Version couldn\'t determined.');
  175.                  */                                     
  176.                 $ver ISBN_VERSION_NONE;
  177.             }
  178.         }
  179.         /* version determined */
  180.         $this->ver $ver;
  181.  
  182.         /* handle a complete invalid ISBN of which a version could
  183.          * not be determined. */
  184.         if ($ver === ISBN_VERSION_NONE{
  185.             $this->setISBN('');
  186.             return;
  187.         }
  188.  
  189.         try {
  190.             $this->setISBN($isbn);
  191.         catch(Exception $e{
  192.             /* the isbn is invalid and not set, sothat this
  193.              * ISBN object will be set to a blank value. */
  194.             $this->setISBN('');
  195.         }
  196.  
  197.     }
  198.     // }}}
  199.  
  200.     // {{{ _extractCheckdigit()
  201.         /**
  202.      * extract Checkdigit of an ISBN-Number
  203.      *
  204.      * @param string $isbnn normalized ISBN string
  205.      *
  206.      * @return string|falseISBN-Body or false if failed
  207.      *
  208.      */
  209.     private static function _extractCheckdigit($isbnn)
  210.     {
  211.         $checkdigit false;
  212.         $checkdigit substr($isbnn-1);
  213.         return (string) $checkdigit;
  214.     }
  215.     // }}}
  216.  
  217.     // {{{ _extractEANPrefix()
  218.         /**
  219.      * extracts EAN-Prefix of a normalized isbn string
  220.      *
  221.      * @param string $isbnn normalized isbn string
  222.      *
  223.      * @return string|falsePrefix or false if failed
  224.      */
  225.     private static function _extractEANPrefix($isbnn)
  226.     {
  227.         $r settype($isbnn'string');
  228.         if ($r === false{
  229.             return false;
  230.         }
  231.         if (strlen($isbnn3{
  232.             return false;
  233.         }
  234.         $prefix substr($isbnn03);
  235.         return $prefix;
  236.     }
  237.     // }}}
  238.  
  239.     // {{{ _extractGroup()
  240.         /**
  241.      * extract Registration Group of an ISBN-Body
  242.      *
  243.      * @param string $isbnbody ISBN-Body
  244.      *
  245.      * @return integer|false   Registration Group or false if failed
  246.      */
  247.     private static function _extractGroup($isbnbody)
  248.     {
  249.         $group   '';
  250.         $subbody '';
  251.  
  252.         $r self::_isbnBodyParts($isbnbody$group$subbody);
  253.         if ($r === false{
  254.             return false;
  255.         }
  256.         return $group;
  257.     }
  258.     // }}}
  259.  
  260.     // {{{ _extractISBNBody()
  261.         /**
  262.      * extract ISBN-Body of an ISBN-Number
  263.      *
  264.      * @param string $isbnn normalized ISBN string
  265.      *
  266.      * @return string|falseISBN-Body or false if failed
  267.      */
  268.     private static function _extractISBNBody($isbnn)
  269.     {
  270.         /* extract */
  271.         $body  false;
  272.         $isbnn = (string) $isbnn;
  273.  
  274.         $l strlen($isbnn);
  275.         if ($l == 10{
  276.             $body =  substr($isbnn0-1);
  277.         elseif ($l == 13{
  278.             $body =  substr($isbnn3-1);
  279.         else {
  280.             return false;
  281.         }
  282.         /* verify */
  283.         $r settype($body'string');
  284.         if ($r === false{
  285.             return false;
  286.         }
  287.         if (strlen($body!= 9{
  288.             return false;
  289.         }
  290.         if (ctype_digit($body=== false{
  291.             return false;
  292.         }
  293.         return $body;
  294.     }
  295.     // }}}
  296.  
  297.     // {{{ _isbnBodyParts()
  298.         /**
  299.      * Get the 2 Parts of the ISBN-Body (ISBN-10/ISBN-13-978)
  300.      *
  301.      * @param string $isbnbody           ISBN-Body
  302.      * @param string &$registrationgroup Registration Group
  303.      * @param string &$isbnsubbody       ISBN-Subbody
  304.      *
  305.      * @return boolean    False if failed, True on success
  306.      *
  307.      * @access private
  308.      */
  309.     private static function _isbnBodyParts($isbnbody
  310.                                            &$registrationgroup
  311.                                            &$isbnsubbody)
  312.     {
  313.         /* validate input (should not be needed, @access private) */
  314.         $r settype($isbnbody'string');
  315.         if ($r === false{
  316.             return false;
  317.         }
  318.         if (strlen($isbnbody!= 9{
  319.             return false;
  320.         }
  321.         if (ctype_digit($isbnbody=== false{
  322.             return false;
  323.         }
  324.         /* extract registraion group
  325.          * boundaries see p.13 2005 handbook
  326.          */
  327.         $boundaries array();
  328.  
  329.         $boundaries[array(    0599991);
  330.         $boundaries[array(60000600993)// Iran 2006-12-05
  331.         $boundaries[array(60100699990);
  332.         $boundaries[array(70000799991);
  333.         $boundaries[array(80000949992);
  334.         $boundaries[array(95000989993);
  335.         $boundaries[array(99000998994);
  336.         $boundaries[array(99900999995);
  337.         /* segment value */
  338.         $segment      substr($isbnbody05);
  339.         $segmentvalue intval($segment);
  340.         /* test segment value against boundaries */
  341.         $r false;
  342.         foreach ($boundaries as $boundary{
  343.             if ($segmentvalue >= $boundary[0&& $segmentvalue <= $boundary[1]{
  344.                 $r $boundary[2];
  345.             }
  346.         }
  347.         if ($r === false{
  348.             return false;
  349.         }
  350.         /* $r is 0 when the boundary is not defined */
  351.         if ($r === 0{
  352.             return false;
  353.         }
  354.         $registrationgroup substr($isbnbody0$r);
  355.         $isbnsubbody       substr($isbnbody$r);
  356.         return true;
  357.     }
  358.     // }}}
  359.  
  360.     // {{{ _isbnSubbodyParts()
  361.         /**
  362.      * Get the 2 Parts of the ISBN-Subbody (ISBN-10/ISBN-13)
  363.      *
  364.      * @param string  $isbnsubbody  ISBN-Subbody
  365.      * @param integer $groupid      Registrationgroup
  366.      * @param string  &$registrant  Registrant
  367.      * @param string  &$publication Publication
  368.      *
  369.      * @return boolean    False if failed, true on success
  370.      *
  371.      * @access private
  372.      */
  373.     private static function _isbnSubbodyParts($isbnsubbody
  374.                                               $groupid
  375.                                               &$registrant
  376.                                               &$publication)
  377.     {
  378.         /* validate input (should not be needed, @access private) */
  379.         $r settype($isbnsubbody'string');
  380.         if ($r === false{
  381.             return false;
  382.         }
  383.         $l strlen($isbnsubbody);
  384.         if $l || $l 8{
  385.             return false;
  386.         }
  387.         if (ctype_digit($isbnsubbody=== false{
  388.             return false;
  389.         }
  390.         $r settype($groupid'integer');
  391.         if ($r === false{
  392.             return false;
  393.         }
  394.         if ($groupid || $groupid 99999{
  395.             return false;
  396.         }
  397.         /* extract registrant based on group and registrant range
  398.          * parse this specific group format: 
  399.          *  array(
  400.          *      'English speaking area',
  401.          *      '00-09;10-19;200-699;7000-8499;85000-89999;' .
  402.          *         '900000-949999;9500000-9999999'
  403.          *      );
  404.          */
  405.         $group self::_getISBN10Group($groupid);
  406.         if ($group === false{
  407.             return false;
  408.         }
  409.         $len self::_getRegistrantLength($isbnsubbody$group[1]);
  410.         if ($len === false{
  411.             return false;
  412.         }
  413.         $registrant  substr($isbnsubbody0$len);
  414.         $publication substr($isbnsubbody$len);
  415.         return true;
  416.     }
  417.     // }}}
  418.  
  419.     // {{{ _getRegistrantLength()
  420.         /**
  421.      * Return Length of Registrant part within an ISBNSubbody in a specific
  422.      * grouprange in this specific format:
  423.      *
  424.      * '00-09;10-19;200-699;7000-8499;85000-89999;900000-949999;9500000-9999999'
  425.      *
  426.      * Info: This function is compatible with Groupranges formatted in the
  427.      * .js file and might become obsolete if new formats are more fitting.
  428.      *
  429.      * @param string $isbnsubbody ISBN-Subbody
  430.      * @param string $grouprange  Grouprange in the Format '#a1-#z1;#a2-z2[...]'
  431.      *
  432.      * @return boolean|int   False if failed or Length (in chars) of Registrant
  433.      *
  434.      * @access private
  435.      */
  436.     private static function _getRegistrantLength($isbnsubbody$grouprange)
  437.     {
  438.         $r settype($grouprange'string');
  439.         if ($r === false{
  440.             return false;
  441.         }
  442.         if (strlen($grouprange3{
  443.             return false;
  444.         }
  445.         $sl     strlen($isbnsubbody);
  446.         $ranges explode(';'$grouprange);
  447.         foreach ($ranges as $range{
  448.             $range  trim($range);
  449.             $fromto explode('-'$range);
  450.             if (count($fromto!== 2{
  451.                 return false;
  452.             }
  453.             /* validation:
  454.              * from and to need to be in the same class,
  455.              * having the same length.
  456.              * registrant can not be bigger or same then the
  457.              * whole subbody, at least there is one digit for
  458.              * the publication.
  459.              */
  460.  
  461.             $l strlen($fromto[0]);
  462.             if ($l != strlen($fromto[1])) {
  463.                 return false;
  464.             }
  465.             if ($l >= $sl{
  466.                 return false;
  467.             }
  468.  
  469.             /* check that from/to values are in order */
  470.             if (strcmp($fromto[0]$fromto[1]>= 0{
  471.                 return false;
  472.             }
  473.  
  474.             /* compare and fire if matched */
  475.             $compare intval(substr($isbnsubbody0$l));
  476.  
  477.             if (strcmp($fromto[0]$compare&& 
  478.                 strcmp($fromto[1]$compare> -1{
  479.                 return $l;
  480.             }
  481.         }
  482.         return false;
  483.     }
  484.     // }}}
  485.  
  486.     // {{{ _getISBN10Group()
  487.         /**
  488.      * Get ISBN-10 Registration Group Data by its numeric ID
  489.      *
  490.      * @param integer $id Registration Group Identifier
  491.      *
  492.      * @return mixed    array:     group array
  493.      *                     boolean: False if failed
  494.      */
  495.     private static function _getISBN10Group($id)
  496.     {
  497.         $r settype($id'integer');
  498.         if ($r === false{
  499.             return false;
  500.         }
  501.         $groups self::_getISBN10Groups();
  502.         if ($groups === false{
  503.             return false;
  504.         }
  505.         if (isset($groups[$id]=== false{
  506.             return false;
  507.         }
  508.         $group $groups[$id];
  509.         return $group;
  510.     }
  511.     // }}}
  512.  
  513.     // {{{ _getISBN10Groups()
  514.         /**
  515.      * Get all ISBN-10 Registration Groups
  516.      *
  517.      * @return array    groups array
  518.      *
  519.      *  Info: This function connects outer world data into this class logic
  520.      *        which can be generated with the supplied tools.
  521.      *          A user should not alter the array data. This data should be altered
  522.      *          together with the international ISBN Agency only.
  523.      */
  524.     private static function _getISBN10Groups()
  525.     {
  526.         $groups array();
  527.         /* ISBN Code-Generator - Ranges */
  528.         $groups[    0array('English speaking area',
  529.                                '00-19;200-699;7000-8499;85000-89999;'.
  530.                                '900000-949999;9500000-9999999');
  531.         $groups[    1array('English speaking area',
  532.                                '00-09;100-399;4000-5499;55000-86979;'.
  533.                                '869800-998999');
  534.         $groups[    2array('French speaking area',
  535.                                '00-19;200-349;35000-39999;400-699;7000-8399;'.
  536.                                '84000-89999;900000-949999;9500000-9999999');
  537.         $groups[    3array('German speaking area',
  538.                                '00-02;030-033;0340-0369;03700-03999;04-19;'.
  539.                                '200-699;7000-8499;85000-89999;900000-949999;'.
  540.                                '9500000-9999999');
  541.         $groups[    4array('Japan',
  542.                                '00-19;200-699;7000-8499;85000-89999;'.
  543.                                '900000-949999;9500000-9999999');
  544.         $groups[    5array('Russian Federation',
  545.                                '00-19;200-699;7000-8499;85000-89999;'.
  546.                                '900000-909999;91000-91999;9200-9299;'.
  547.                                '93000-94999;9500-9799;98000-98999;'.
  548.                                '9900000-9909999;9910-9999');
  549.         $groups[  600array('Iran',
  550.                                '00-09;100-499;5000-8999;90000-99999');
  551.         $groups[    7array('China, People\'s Republic',
  552.                                '00-09;100-499;5000-7999;80000-89999;'.
  553.                                '900000-999999');
  554.         $groups[   80array('Czech Republic; Slovakia',
  555.                                '00-19;200-699;7000-8499;85000-89999;'.
  556.                                '900000-999999');
  557.         $groups[   81array('India',
  558.                                '00-19;200-699;7000-8499;85000-89999;'.
  559.                                '900000-999999');
  560.         $groups[   82array('Norway',
  561.                                '00-19;200-699;7000-8999;90000-98999;'.
  562.                                '990000-999999');
  563.         $groups[   83array('Poland',
  564.                                '00-19;200-599;60000-69999;7000-8499;'.
  565.                                '85000-89999;900000-999999');
  566.         $groups[   84array('Spain',
  567.                                '00-19;200-699;7000-8499;85000-89999;9000-9199;'.
  568.                                '920000-923999;92400-92999;930000-949999;'.
  569.                                '95000-96999;9700-9999');
  570.         $groups[   85array('Brazil',
  571.                                '00-19;200-599;60000-69999;7000-8499;'.
  572.                                '85000-89999;900000-979999;98000-99999');
  573.         $groups[   86array('Serbia and Montenegro',
  574.                                '00-29;300-599;6000-7999;80000-89999;'.
  575.                                '900000-999999');
  576.         $groups[   87array('Denmark',
  577.                                '00-29;400-649;7000-7999;85000-94999;'.
  578.                                '970000-999999');
  579.         $groups[   88array('Italian speaking area',
  580.                                '00-19;200-599;6000-8499;85000-89999;'.
  581.                                '900000-949999;95000-99999');
  582.         $groups[   89array('Korea',
  583.                                '00-24;250-549;5500-8499;85000-94999;'.
  584.                                '950000-999999');
  585.         $groups[   90array('Netherlands, Belgium (Flemish)',
  586.                                '00-19;200-499;5000-6999;70000-79999;'.
  587.                                '800000-849999;8500-8999;900000-909999;'.
  588.                                '940000-949999');
  589.         $groups[   91array('Sweden',
  590.                                '0-1;20-49;500-649;7000-7999;85000-94999;'.
  591.                                '970000-999999');
  592.         $groups[   92array('International Publishers (Unesco, EU), Europe...',
  593.                                '0-5;60-79;800-899;9000-9499;95000-98999;'.
  594.                                '990000-999999');
  595.         $groups[   93array('India - no ranges fixed yet','');
  596.         $groups[  950array('Argentina',
  597.                                '00-49;500-899;9000-9899;99000-99999');
  598.         $groups[  951array('Finland',
  599.                                '0-1;20-54;550-889;8900-9499;95000-99999');
  600.         $groups[  952array('Finland',
  601.                                '00-19;200-499;5000-5999;60-65;6600-6699;'.
  602.                                '67000-69999;7000-7999;80-94;9500-9899;'.
  603.                                '99000-99999');
  604.         $groups[  953array('Croatia',
  605.                                '0-0;10-14;150-549;55000-59999;6000-9499;'.
  606.                                '95000-99999');
  607.         $groups[  954array('Bulgaria',
  608.                                '00-29;300-799;8000-8999;90000-92999;9300-9999');
  609.         $groups[  955array('Sri Lanka',
  610.                                '0-0;1000-1999;20-54;550-799;8000-9499;'.
  611.                                '95000-99999');
  612.         $groups[  956array('Chile',
  613.                                '00-19;200-699;7000-9999');
  614.         $groups[  957array('Taiwan, China',
  615.                                '00-02;0300-0499;05-19;2000-2099;21-27;'.
  616.                                '28000-30999;31-43;440-819;8200-9699;'.
  617.                                '97000-99999');
  618.         $groups[  958array('Colombia',
  619.                                '00-59;600-799;8000-9499;95000-99999');
  620.         $groups[  959array('Cuba',
  621.                                '00-19;200-699;7000-8499');
  622.         $groups[  960array('Greece',
  623.                                '00-19;200-659;6600-6899;690-699;7000-8499;'.
  624.                                '85000-99999');
  625.         $groups[  961array('Slovenia',
  626.                                '00-19;200-599;6000-8999;90000-94999');
  627.         $groups[  962array('Hong Kong',
  628.                                '00-19;200-699;7000-8499;85000-86999;8700-8999;'.
  629.                                '900-999');
  630.         $groups[  963array('Hungary',
  631.                                '00-19;200-699;7000-8499;85000-89999;9000-9999');
  632.         $groups[  964array('Iran',
  633.                                '00-14;150-249;2500-2999;300-549;5500-8999;'.
  634.                                '90000-96999;970-989;9900-9999');
  635.         $groups[  965array('Israel',
  636.                                '00-19;200-599;7000-7999;90000-99999');
  637.         $groups[  966array('Ukraine',
  638.                                '00-19;2000-2999;300-699;7000-8999;90000-99999');
  639.         $groups[  967array('Malaysia',
  640.                                '0-5;60-89;900-989;9900-9989;99900-99999');
  641.         $groups[  968array('Mexico',
  642.                                '01-39;400-499;5000-7999;800-899;9000-9999');
  643.         $groups[  969array('Pakistan',
  644.                                '0-1;20-39;400-799;8000-9999');
  645.         $groups[  970array('Mexico',
  646.                                '01-59;600-899;9000-9099;91000-96999;9700-9999');
  647.         $groups[  971array('Philippines?',
  648.                                '000-019;02-02;0300-0599;06-09;10-49;500-849;'.
  649.                                '8500-9099;91000-99999');
  650.         $groups[  972array('Portugal',
  651.                                '0-1;20-54;550-799;8000-9499;95000-99999');
  652.         $groups[  973array('Romania',
  653.                                '0-0;100-169;1700-1999;20-54;550-759;7600-8499;'.
  654.                                '85000-88999;8900-9499;95000-99999');
  655.         $groups[  974array('Thailand',
  656.                                '00-19;200-699;7000-8499;85000-89999;'.
  657.                                '90000-94999;9500-9999');
  658.         $groups[  975array('Turkey',
  659.                                '00000-00999;01-24;250-599;6000-9199;'.
  660.                                '92000-98999;990-999');
  661.         $groups[  976array('Caribbean Community',
  662.                                '0-3;40-59;600-799;8000-9499;95000-99999');
  663.         $groups[  977array('Egypr',
  664.                                '00-19;200-499;5000-6999;700-999');
  665.         $groups[  978array('Nigeria',
  666.                                '000-199;2000-2999;30000-79999;8000-8999;'.
  667.                                '900-999');
  668.         $groups[  979array('Indonesia',
  669.                                '000-099;1000-1499;15000-19999;20-29;3000-3999;'.
  670.                                '400-799;8000-9499;95000-99999');
  671.         $groups[  980array('Venezuela',
  672.                                '00-19;200-599;6000-9999');
  673.         $groups[  981array('Singapore',
  674.                                '00-19;200-299;3000-9999');
  675.         $groups[  982array('South Pacific',
  676.                                '00-09;100-699;70-89;9000-9999');
  677.         $groups[  983array('Malaysia',
  678.                                '00-01;020-199;2000-3999;40000-49999;50-79;'.
  679.                                '800-899;9000-9899;99000-99999');
  680.         $groups[  984array('Bangladesh',
  681.                                '00-39;400-799;8000-8999;90000-99999');
  682.         $groups[  985array('Belarus',
  683.                                '00-39;400-599;6000-8999;90000-99999');
  684.         $groups[  986array('Taiwan, China',
  685.                                '00-11;120-559;5600-7999;80000-99999');
  686.         $groups[  987array('Argentina',
  687.                                '00-09;1000-1999;20000-29999;30-49;500-899;'.
  688.                                '9000-9499;95000-99999');
  689.         $groups[  988array('Hongkong',
  690.                                '00-19;200-799;8000-9699;97000-99999');
  691.         $groups[  989array('Portugal',
  692.                                '0-1;20-54;550-799;8000-9499;95000-99999');
  693.         $groups9940array('Montenegro',
  694.                                '0-1;20-49;500-899;9000-9999');
  695.         $groups9941array('Georgia',
  696.                                '0-0;10-39;400-899;9000-9999');
  697.         $groups9942array('Ecuador',
  698.                                '00-89;900-994;9950-9999');
  699.         $groups9943array('Uzbekistan',
  700.                                '00-29;300-399;4000-9999');
  701.         $groups9944array('Turkey',
  702.                                '0-2;300-499;5000-5999;60-89;900-999');
  703.         $groups9945array('Dominican Republic',
  704.                                '00-00;010-079;08-39;400-569;57-57;580-849;'.
  705.                                '8500-9999');
  706.         $groups9946array('Korea, P.D.R.',
  707.                                '0-1;20-39;400-899;9000-9999');
  708.         $groups9947array('Algeria',
  709.                                '0-1;20-79;800-999');
  710.         $groups9948array('United Arab Emirates',
  711.                                '00-39;400-849;8500-9999');
  712.         $groups9949array('Estonia',
  713.                                '0-0;10-39;400-899;9000-9999');
  714.         $groups9950array('Palestine',
  715.                                '00-29;300-840;8500-9999');
  716.         $groups9951array('Kosova',
  717.                                '00-39;400-849;8500-9999');
  718.         $groups9952array('Azerbaijan',
  719.                                '0-1;20-39;400-799;8000-9999');
  720.         $groups9953array('Lebanon',
  721.                                '0-0;10-39;400-599;60-89;9000-9999');
  722.         $groups9954array('Morocco',
  723.                                '0-1;20-39;400-799;8000-9999');
  724.         $groups9955array('Lithuania',
  725.                                '00-39;400-929;9300-9999');
  726.         $groups9956array('Cameroon',
  727.                                '0-0;10-39;400-899;9000-9999');
  728.         $groups9957array('Jordan',
  729.                                '00-39;400-849;8500-9999');
  730.         $groups9958array('Bosnia and Herzegovina',
  731.                                '0-0;10-49;500-899;9000-9999');
  732.         $groups9959array('Libya',
  733.                                '0-1;20-79;800-949;9500-9999');
  734.         $groups9960array('Saudi Arabia',
  735.                                '00-59;600-899;9000-9999');
  736.         $groups9961array('Algeria',
  737.                                '0-2;30-69;700-949;9500-9999');
  738.         $groups9962array('Panama',
  739.                                '00-54;5500-5599;56-59;600-849;8500-9999');
  740.         $groups9963array('Cyprus',
  741.                                '0-2;30-54;550-749;7500-9999');
  742.         $groups9964array('Ghana',
  743.                                '0-6;70-94;950-999');
  744.         $groups9965array('Kazakhstan',
  745.                                '00-39;400-899;9000-9999');
  746.         $groups9966array('Kenya',
  747.                                '00-69;7000-7499;750-959;9600-9999');
  748.         $groups9967array('Kyrgyzstan',
  749.                                '00-39;400-899;9000-9999');
  750.         $groups9968array('Costa Rica',
  751.                                '00-49;500-939;9400-9999');
  752.         $groups9970array('Uganda',
  753.                                '00-39;400-899;9000-9999');
  754.         $groups9971array('Singapore',
  755.                                '0-5;60-89;900-989;9900-9999');
  756.         $groups9972array('Peru',
  757.                                '00-09;1;200-249;2500-2999;30-59;600-899;'.
  758.                                '9000-9999');
  759.         $groups9973array('Tunisia',
  760.                                '0-0;10-69;700-969;9700-9999');
  761.         $groups9974array('Uruguay',
  762.                                '0-2;30-54;550-749;7500-9499;95-99');
  763.         $groups9975array('Moldova',
  764.                                '0;100-399;4000-4499;45-89;900-949;9500-9999');
  765.         $groups9976array('Tanzania',
  766.                                '0-5;60-89;900-989;9990-9999');
  767.         $groups9977array('Costa Rica',
  768.                                '00-89;900-989;9900-9999');
  769.         $groups9978array('Ecuador',
  770.                                '00-29;300-399;40-94;950-989;9900-9999');
  771.         $groups9979array('Iceland',
  772.                                '0-4;50-64;650-659;66-75;760-899;9000-9999');
  773.         $groups9980array('Papua New Guinea',
  774.                                '0-3;40-89;900-989;9900-9999');
  775.         $groups9981array('Morocco',
  776.                                '00-09;100-159;1600-1999;20-79;800-949;'.
  777.                                '9500-9999');
  778.         $groups9982array('Zambia',
  779.                                '00-79;800-889;9900-9999');
  780.         $groups9983array('Gambia',
  781.                                '80-94;950-989;9900-9999');
  782.         $groups9984array('Latvia',
  783.                                '00-49;500-899;9000-9999');
  784.         $groups9985array('Estonia',
  785.                                '0-4;50-79;800-899;9000-9999');
  786.         $groups9986array('Lithuania',
  787.                                '00-39;400-899;9000-9399;940-969;97-99');
  788.         $groups9987array('Tanzania',
  789.                                '00-39;400-879;8800-9999');
  790.         $groups9988array('Ghana',
  791.                                '0-2;30-54;550-749;7500-9999');
  792.         $groups9989array('Macedonia',
  793.                                '0-0;100-199;2000-2999;30-59;600-949;9500-9999');
  794.         $groups[99901array('Bahrain',
  795.                                '00-49;500-799;80-99');
  796.         $groups[99902array('Gabon - no ranges fixed yet','');
  797.         $groups[99903array('Mauritius',
  798.                                '0-1;20-89;900-999');
  799.         $groups[99904array('Netherlands Antilles; Aruba, Neth. Ant',
  800.                                '0-5;60-89;900-999');
  801.         $groups[99905array('Bolivia',
  802.                                '0-3;40-79;800-999');
  803.         $groups[99906array('Kuwait',
  804.                                '0-2;30-59;600-699;70-89;9-9');
  805.         $groups[99908array('Malawi',
  806.                                '0-0;10-89;900-999');
  807.         $groups[99909array('Malta',
  808.                                '0-3;40-94;950-999');
  809.         $groups[99910array('Sierra Leone',
  810.                                '0-2;30-89;900-999');
  811.         $groups[99911array('Lesotho',
  812.                                '00-59;600-999');
  813.         $groups[99912array('Botswana',
  814.                                '0-3;400-599;60-89;900-999');
  815.         $groups[99913array('Andorra',
  816.                                '0-2;30-35;600-604');
  817.         $groups[99914array('Suriname',
  818.                                '0-4;50-89;900-949');
  819.         $groups[99915array('Maldives',
  820.                                '0-4;50-79;800-999');
  821.         $groups[99916array('Namibia',
  822.                                '0-2;30-69;700-999');
  823.         $groups[99917array('Brunei Darussalam',
  824.                                '0-2;30-89;900-999');
  825.         $groups[99918array('Faroe Islands',
  826.                                '0-3;40-79;800-999');
  827.         $groups[99919array('Benin',
  828.                                '0-2;40-69;900-999');
  829.         $groups[99920array('Andorra',
  830.                                '0-4;50-89;900-999');
  831.         $groups[99921array('Qatar',
  832.                                '0-1;20-69;700-799;8-8;90-99');
  833.         $groups[99922array('Guatemala',
  834.                                '0-3;40-69;700-999');
  835.         $groups[99923array('El Salvador',
  836.                                '0-1;20-79;800-999');
  837.         $groups[99924array('Nicaragua',
  838.                                '0-2;30-79;800-999');
  839.         $groups[99925array('Paraguay',
  840.                                '0-3;40-79;800-999');
  841.         $groups[99926array('Honduras',
  842.                                '0-0;10-59;600-999');
  843.         $groups[99927array('Albania',
  844.                                '0-2;30-59;600-999');
  845.         $groups[99928array('Georgia',
  846.                                '0-0;10-79;800-999');
  847.         $groups[99929array('Mongolia',
  848.                                '0-4;50-79;800-999');
  849.         $groups[99930array('Armenia',
  850.                                '0-4;50-79;800-999');
  851.         $groups[99931array('Seychelles',
  852.                                '0-4;50-79;800-999');
  853.         $groups[99932array('Malta',
  854.                                '0-0;10-59;600-699;7-7;80-99');
  855.         $groups[99933array('Nepal',
  856.                                '0-2;30-59;600-999');
  857.         $groups[99934array('Dominican Republic',
  858.                                '0-1;20-79;800-999');
  859.         $groups[99935array('Haiti',
  860.                                '0-2;7-8;30-59;600-699;90-99');
  861.         $groups[99936array('Bhutan',
  862.                                '0-0;10-59;600-999');
  863.         $groups[99937array('Macau',
  864.                                '0-1;20-59;600-999');
  865.         $groups[99938array('Srpska',
  866.                                '0-1;20-59;600-899;90-99');
  867.         $groups[99939array('Guatemala',
  868.                                '0-5;60-89;900-999');
  869.         $groups[99940array('Georgia',
  870.                                '0-0;10-69;700-999');
  871.         $groups[99941array('Armenia',
  872.                                '0-2;30-79;800-999');
  873.         $groups[99942array('Sudan',
  874.                                '0-4;50-79;800-999');
  875.         $groups[99943array('Alsbania',
  876.                                '0-2;30-59;600-999');
  877.         $groups[99944array('Ethiopia',
  878.                                '0-4;50-79;800-999');
  879.         $groups[99945array('Namibia',
  880.                                '0-5;60-89;900-999');
  881.         $groups[99946array('Nepal',
  882.                                '0-2;30-59;600-999');
  883.         $groups[99947array('Tajikistan',
  884.                                '0-2;30-69;700-999');
  885.         $groups[99948array('Eritrea',
  886.                                '0-4;50-79;800-999');
  887.         $groups[99949array('Mauritius',
  888.                                '0-1;20-89;900-999');
  889.         $groups[99950array('Cambodia',
  890.                                '0-4;50-79;800-999');
  891.         $groups[99951array('Congo - no ranges fixed yet','');
  892.         $groups[99952array('Mali',
  893.                                '0-4;50-79;800-999');
  894.         $groups[99953array('Paraguay',
  895.                                '0-2;30-79;800-999');
  896.         $groups[99954array('Bolivia',
  897.                                '0-2;30-69;700-999');
  898.         $groups[99955array('Srpska',
  899.                                '0-1;20-59;600-899;90-99');
  900.         return $groups;
  901.     }
  902.     // }}}
  903.  
  904.     // {{{ _getVersion()
  905.         /**
  906.      * Get the Version of am ISBN Number
  907.      *
  908.      * @param string $isbn ISBN Number ofwhich the version to get
  909.      *
  910.      * @return mixed false for no, or fully identifyable ISBN
  911.      *                                 Version Constant
  912.      *
  913.      * @access private
  914.      */
  915.     private static function _getVersion($isbn)
  916.     {
  917.         $ver self::_isbnVersionGuess($isbn);
  918.         $r   self::_isbnVersionIsValid($ver);
  919.         return $r;
  920.     }
  921.     // }}}
  922.  
  923.     // {{{ _checkdigitISBN10()
  924.           /**
  925.      * Calculate checkdigit of an ISBN-10 string (ISBN-Body)
  926.      * as documented on pp.4-5 2001 handbook.
  927.      *
  928.      * @param string $isbnbody ISBN-Body
  929.      *
  930.      * @return string|falseCheckdigit [0-9,X] or false if failed
  931.      *
  932.      * @access private
  933.      */
  934.     private static function _checkdigitISBN10($isbnbody)
  935.     {
  936.         /* The check digit is the last digit of an ISBN. It is calculated
  937.          * on a modulus 11 with weights 10-2, using X in lieu of 10 where
  938.          * ten would occur as a check digit.
  939.          * This means that each of the first nine digits of the ISBN ï¿½
  940.          * excluding the check digit itself ï¿½ is multiplied by a number
  941.          * ranging from 10 to 2 and that the resulting sum of the products,
  942.          * plus the check digit, must be divisible by 11 without a
  943.          * remainder. (pp.4-5 2001 Handbook)
  944.          */
  945.         if (strlen($isbnbody!= 9{
  946.             return false;
  947.         }
  948.         $sum 0;
  949.         for ($i 0$i 10$i++{
  950.             $v    intval(substr($isbnbody$i1));
  951.             $sum += $v (10 $i);
  952.         }
  953.         $remainder  $sum 11;
  954.         $checkdigit 11 $remainder;
  955.         if ($remainder == 0{
  956.             $checkdigit 0;
  957.         }
  958.         if ($checkdigit == 10{
  959.             $checkdigit 'X';
  960.         }
  961.         return (string) $checkdigit;
  962.     }
  963.     // }}}
  964.  
  965.     // {{{ _checkdigitISBN13()
  966.           /**
  967.      * Calculate checkdigit of an ISBN-13 string (Prefix + ISBN-Body)
  968.      * as documented on pp.10-11 2005 handbook.
  969.      *
  970.      * @param string $isbnbody ISBN-Body
  971.      * @param string $prefix   EAN-Prefix (Default 978 for ISBN13-978)
  972.      *
  973.      * @return string|falseCheckdigit [0-9] or false if failed
  974.      *
  975.      * @access private
  976.      */
  977.     private static function _checkdigitISBN13($isbnbody$prefix '978')
  978.     {
  979.         $prefixandisbnbody $prefix $isbnbody;
  980.  
  981.         $t $prefixandisbnbody;
  982.         $l strlen($t);
  983.         if ($l != 12{
  984.             return false;
  985.         }
  986.         /* Step 1: Determine the sum of the weighted products for the first 12
  987.         *  digits of the ISBN (see p.10 2005 handbook)
  988.         */
  989.         $ii 1;
  990.         $sum 0;
  991.         for ($i 0$i 13$i++{
  992.             $ii   $ii;
  993.             $sum += intval(substr($t$i1)) ($ii 1);
  994.         }
  995.         /* Step 2: Divide the sum of the weighted products of the first 12
  996.          * digits of the ISBN calculated in step 1 by 10, determining the
  997.          * remainder. (see p.11 2005 handbook)
  998.          */
  999.         $remainder $sum 10;
  1000.  
  1001.         /* Step 3: Subtract the remainder calculated in step 2 from 10. The
  1002.          * resulting difference is the value of the check digit with one
  1003.          * exception. If the remainder from step 2 is 0, the check
  1004.          * digit is 0. (ebd.)
  1005.          */
  1006.         $checkdigit 10 $remainder;
  1007.         if ($remainder == 0{
  1008.             $checkdigit 0;
  1009.         }
  1010.         /* return string value */
  1011.         if (is_int($checkdigit)) {
  1012.             $checkdigit = (string) $checkdigit;
  1013.         }
  1014.         if (is_string($checkdigit== false{
  1015.             return false;
  1016.         }
  1017.         return $checkdigit;
  1018.     }
  1019.     // }}}
  1020.  
  1021.     // {{{ _isIsbnValid()
  1022.         /**
  1023.      * Validate an ISBN value
  1024.      *
  1025.      * @param string $isbn Number to validate
  1026.      * @param string $ver  Version to validate against
  1027.      *
  1028.      * @return integer|false   Returns the Version to signal validity or false if
  1029.      *                             ISBN number is not valid
  1030.      *
  1031.      * @access private
  1032.      */
  1033.     private static function _isIsbnValid($isbn$ver ISBN_DEFAULT_INPUTVERSION)
  1034.     {
  1035.         /* version handling */
  1036.         $r self::_isbnVersionIs($ver);
  1037.         if ($r === false{
  1038.             return false;
  1039.         }
  1040.         if ($ver === ISBN_VERSION_UNKNOWN{
  1041.             $ver self::_isbnVersionGuess($isbn);
  1042.         }
  1043.         if (self::_isbnVersionIsValid($ver=== false{
  1044.             return false;
  1045.         }
  1046.         /* since a version is available now, normalise the ISBN input */
  1047.         $isbnn self::_normaliseISBN($isbn);
  1048.         if ($isbnn === false{
  1049.             return false;
  1050.         }
  1051.         /* normalzied ISBN and Version available, it's ok now
  1052.          * to perform indepth checks per version */
  1053.         switch ($ver{
  1054.         case ISBN_VERSION_ISBN_10:
  1055.  
  1056.             /* check syntax against checkdigit */
  1057.             $isbnbody self::_extractISBNBody($isbnn);
  1058.             $check    self::_extractCheckdigit($isbnn);
  1059.             if ($check === false{
  1060.                 return false;
  1061.             }
  1062.             $checkdigit self::_checkdigitISBN10($isbnbody);
  1063.             if ($checkdigit === false{
  1064.                 return false;
  1065.             }
  1066.             if ($checkdigit !== $check{
  1067.                 return false;
  1068.             }
  1069.  
  1070.             /* check registrationgroup validity */
  1071.             $registrationgroup false;
  1072.             $subbody           false;
  1073.  
  1074.             $r self::_isbnBodyParts($isbnbody$registrationgroup$subbody);
  1075.             if ($r == false{
  1076.                 return false;
  1077.             }
  1078.  
  1079.             /* check for undefined registrationgroup */
  1080.             if (strlen($registrationgroup== 0{
  1081.                 return false;
  1082.             }
  1083.  
  1084.             /* check registrant validity */
  1085.             $groupid     intval($registrationgroup);
  1086.             $registrant  false;
  1087.             $publication false;
  1088.  
  1089.             $r self::_isbnSubbodyParts($subbody$groupid
  1090.                                          $registrant$publication);
  1091.             if ($r == false{
  1092.                 return false;
  1093.             }
  1094.             return true;
  1095.  
  1096.         case ISBN_VERSION_ISBN_13:
  1097.         case ISBN_VERSION_ISBN_13_978:
  1098.  
  1099.             /* validate EAN Prefix */
  1100.             $ean self::_extractEANPrefix($isbnn);
  1101.             if ($ean !== '978'{
  1102.                 return false;
  1103.             }
  1104.  
  1105.             /* check syntax against checkdigit */
  1106.             $isbnbody self::_extractISBNBody($isbnn);
  1107.             $check    self::_extractCheckdigit($isbnn);
  1108.             if ($check === false{
  1109.                 return false;
  1110.             }
  1111.             $checkdigit self::_checkdigitISBN13($isbnbody);
  1112.             if ($checkdigit === false{
  1113.                 return false;
  1114.             }
  1115.             if ($check !== $checkdigit{
  1116.                 return false;
  1117.             }
  1118.  
  1119.             /* validate group */
  1120.             $isbnbody self::_extractISBNBody($isbnn);
  1121.             if ($isbnbody === false{
  1122.                 return false;
  1123.             }
  1124.  
  1125.             $registrationgroup false;
  1126.             $subbody           false;
  1127.  
  1128.             $r self::_isbnBodyParts($isbnbody$registrationgroup$subbody);
  1129.             if ($r === false{
  1130.                 return false;
  1131.             }
  1132.  
  1133.             /* check for undefined registrationgroup */
  1134.             if (strlen($registrationgroup== 0{
  1135.                 return false;
  1136.             }
  1137.  
  1138.             /* validate publisher */
  1139.             $registrant  false;
  1140.             $publication false;
  1141.  
  1142.             $r self::_isbnSubbodyParts($subbody$registrationgroup
  1143.                                          $registrant$publication);
  1144.             if ($r === false{
  1145.                 return false;
  1146.             }
  1147.             return $ver;
  1148.  
  1149.         case ISBN_VERSION_ISBN_13_979:
  1150.             /* not yet standarized */
  1151.             return false;
  1152.  
  1153.         }
  1154.         return false;
  1155.     }
  1156.     // }}}
  1157.  
  1158.     // {{{ _isbnVersionGuess()
  1159.         /**
  1160.      * Guesses the version of an ISBN
  1161.      *
  1162.      * @param string $isbn ISBN Number of which the Version to guess
  1163.      *
  1164.      * @return integer|falseVersion Value or false (ISBN_VERSION_NONE) if failed
  1165.      * @access private
  1166.      */
  1167.     private static function _isbnVersionGuess($isbn)
  1168.     {
  1169.         $isbn self::_normaliseISBN($isbn);
  1170.         if ($isbn === false{
  1171.             return ISBN_VERSION_NONE;
  1172.         }
  1173.         if strlen($isbn== 10{
  1174.             return ISBN_VERSION_ISBN_10;
  1175.         else {
  1176.             return ISBN_VERSION_ISBN_13;
  1177.         }
  1178.     }
  1179.     // }}}
  1180.  
  1181.     // {{{ _isbnVersionIs()
  1182.         /**
  1183.      * Validate an ISBN Version value
  1184.      *
  1185.      * @param mixed $ver version to be checked being a valid ISBN Version
  1186.      *
  1187.      * @return bool    true if value is valid, false if not
  1188.      *
  1189.      * @access private
  1190.      */
  1191.     private static function _isbnVersionIs($ver)
  1192.     {
  1193.         if (is_bool($ver=== false && is_integer($ver=== false{
  1194.             return false;
  1195.         }
  1196.         switch ($ver{
  1197.         case ISBN_VERSION_NONE:
  1198.         case ISBN_VERSION_UNKNOWN:
  1199.         case ISBN_VERSION_ISBN_10:
  1200.         case ISBN_VERSION_ISBN_13:
  1201.         case ISBN_VERSION_ISBN_13_978:
  1202.         case ISBN_VERSION_ISBN_13_979:
  1203.             return true;
  1204.  
  1205.         default:
  1206.             return false;
  1207.  
  1208.         }
  1209.     }
  1210.     // }}}
  1211.  
  1212.     // {{{ _isbnVersionIsValid()
  1213.         /**
  1214.      * Validate an ISBN value being a valid (identifyable -10 / -13) value
  1215.      *
  1216.      * @param mixed $ver value to be checked being a valid ISBN Version
  1217.      *
  1218.      * @return bool    true if value is valid, false if not
  1219.      *
  1220.      * @access private
  1221.      */
  1222.     private static function _isbnVersionIsValid($ver)
  1223.     {
  1224.         $r self::_isbnVersionIs($ver);
  1225.         if ($r === false{
  1226.             return false;
  1227.         }
  1228.  
  1229.         switch ($ver{
  1230.         case ISBN_VERSION_ISBN_10:
  1231.         case ISBN_VERSION_ISBN_13_978:
  1232.             return true;
  1233.         default:
  1234.             return false;
  1235.         }
  1236.     }
  1237.     // }}}
  1238.  
  1239.     // {{{ _normaliseISBN()
  1240.         /**
  1241.      * downformat "any" ISBN Number to the very basics
  1242.      * an isbn number is a 10 or 13 digit. with the
  1243.      * 10 digit string, the last digit can be 0-9 and
  1244.      * X as well, all other are 0-9 only
  1245.      * additionally this fucntion can be used to validate
  1246.      * the isbn against correct length and chars
  1247.      *
  1248.      * @param string $isbn ISBN String to normalise
  1249.      *
  1250.      * @return string|falsenormalised ISBN Number or false if the function was
  1251.      *                         not able to normalise the input
  1252.      *
  1253.      * @access private
  1254.      */
  1255.     private static function _normaliseISBN($isbn)
  1256.     {
  1257.         /* validate input */
  1258.         $r settype($isbn'string');
  1259.         if ($r === false{
  1260.             return false;
  1261.         }
  1262.  
  1263.         /* normalize (trim & case)*/
  1264.         $isbn trim($isbn);
  1265.         $isbn strtoupper($isbn);
  1266.  
  1267.         /* remove lang specific prefix (if any) */
  1268.         $isbn self::_normaliseISBNremoveLangSpecific($isbn);
  1269.  
  1270.         /* remove ISBN-10: or ISBN-13: prefix (if any) */
  1271.         if (strlen($isbn 8)) {
  1272.             $prefix substr($isbn08);
  1273.             if ($prefix == 'ISBN-10:' || $prefix == 'ISBN-13:'{
  1274.                 $isbn substr($isbn8);
  1275.                 $isbn ltrim($isbn);
  1276.             }
  1277.         }
  1278.  
  1279.         /* remove lang specific prefix again (if any) */
  1280.         $isbn self::_normaliseISBNremoveLangSpecific($isbn);
  1281.  
  1282.         /* remove "ISBN" prefix (if any)*/
  1283.         if (substr($isbn04== 'ISBN'{
  1284.             $isbn substr($isbn4);
  1285.         }
  1286.  
  1287.         /* remove cosmetic chars and different type of spaces */
  1288.         $isbn str_replace(array('-'' ''\t''\n')''$isbn);
  1289.  
  1290.         /* take the length to check and differ between versions
  1291.          * sothat a syntaxcheck can be made */
  1292.         $l strlen($isbn);
  1293.         if ($l != 10 && $l != 13{
  1294.             return false;
  1295.         elseif ($l == 10{
  1296.             if (!preg_match('/^[0-9]{9}[0-9X]$/'$isbn)) {
  1297.                 return false;
  1298.             }
  1299.         elseif ($l == 13{
  1300.             if (!ctype_digit($isbn)) {
  1301.                 return false;
  1302.             }
  1303.         }
  1304.         return $isbn;
  1305.     }
  1306.     // }}}
  1307.  
  1308.     // {{{ _normaliseISBNremoveLangSpecific()
  1309.         /**
  1310.      * helper function for _normaliseISBN to
  1311.      * remove lang sepcific ISBN prefix
  1312.      *
  1313.      * @param string $isbn ISBN String to check (partially normalised)
  1314.      *
  1315.      * @return string    input value passed through helper
  1316.      *
  1317.      * @access private
  1318.      */
  1319.     private static function _normaliseISBNremoveLangSpecific($isbn)
  1320.     {
  1321.         $l    strlen($lang);
  1322.         if ($l {
  1323.             if (substr($isbn0$l== $lang{
  1324.                 $isbn substr($isbn$l);
  1325.             }
  1326.         }
  1327.         return $isbn;
  1328.     }
  1329.     // }}}
  1330.  
  1331.     // {{{ convert()
  1332.         /**
  1333.      * converts an ISBN number from one version to another
  1334.      *
  1335.      * @param string  $isbnin  ISBN to convert, must be a valid ISBN Number
  1336.      * @param integer $verfrom version value of the input ISBN
  1337.      * @param integer $verto   version value to convert to
  1338.      *
  1339.      * @return string|falseconverted ISBN Number or false if conversion failed
  1340.      */
  1341.     public static function convert($isbnin$verfrom ISBN_VERSION_ISBN_10
  1342.                                    $verto ISBN_VERSION_ISBN_13)
  1343.     {
  1344.         /* validate input */
  1345.         if (!self::_isbnVersionIsValid($verfrom)) {
  1346.             return false;
  1347.         }
  1348.         if (!self::_isbnVersionIsValid($verto)) {
  1349.             return false;
  1350.         }
  1351.         $r self::validate($isbnin$verfrom);
  1352.         if ($r === false{
  1353.             return false;
  1354.         }
  1355.         /* normalize input */
  1356.         $isbnn self::_normaliseISBN($isbnin);
  1357.         /* input is ok now, let's convert */
  1358.         switch(true{
  1359.         case $verfrom == ISBN_VERSION_ISBN_10 && $verto == ISBN_VERSION_ISBN_13:
  1360.             /* convert 10 to 13 */
  1361.             $isbnbody self::_extractISBNBody($isbnn);
  1362.             if ($isbnbody === false{
  1363.                 return false;
  1364.             }
  1365.             $isbnout '978' $isbnbody self::_checkdigitISBN13($isbnbody);
  1366.             return $isbnout;
  1367.         }
  1368.         return false;
  1369.     }
  1370.     // }}}
  1371.  
  1372.     // {{{ getCheckdigit()
  1373.         /**
  1374.      * Get the Checkdigit Part of ISBN Number
  1375.      *
  1376.      * @return string|falseCheckdigit or false if failed
  1377.      */
  1378.     public function getCheckdigit()
  1379.     {
  1380.         $ver   $this->getVersion();
  1381.         $check false;
  1382.  
  1383.         switch ($ver{
  1384.         case ISBN_VERSION_ISBN_10:
  1385.             $check self::_checkdigitISBN10($this->_getISBNBody());
  1386.             break;
  1387.  
  1388.         case ISBN_VERSION_ISBN_13:
  1389.             $check self::_checkdigitISBN13($this->_getISBNBody());
  1390.             break;
  1391.  
  1392.         }
  1393.  
  1394.         return $check;
  1395.     }
  1396.     // }}}
  1397.  
  1398.     // {{{ getEAN()
  1399.         /**
  1400.      * Get the EAN Prefix of ISBN Number (ISBN-13)
  1401.      *
  1402.      * @return string|falseEAN Prefix or false if failed
  1403.      */
  1404.     public function getEAN()
  1405.     {
  1406.         $ver $this->getVersion();
  1407.         if ($ver === false {
  1408.             return false;
  1409.         }
  1410.         if ($ver == ISBN_VERSION_ISBN_13_978{
  1411.             return '978';
  1412.         }
  1413.         if ($ver == ISBN_VERSION_ISBN_13_979{
  1414.             return '979';
  1415.         }
  1416.         return '';
  1417.     }
  1418.     // }}}
  1419.  
  1420.     // {{{ getGroup()
  1421.         /**
  1422.      * Get the Registrationgroup Part of the ISBN Number
  1423.      *
  1424.      * @return string|falseGroup Identifier or false if failed
  1425.      */
  1426.     public function getGroup()
  1427.     {
  1428.         return $this->isbn_group;
  1429.     }
  1430.     // }}}
  1431.  
  1432.     // {{{ _setGroup()
  1433.         /**
  1434.      * Setter for the Registrationgroup Part of the ISBN Number
  1435.      *
  1436.      * @param string $group Registrationsgroup to set
  1437.      * 
  1438.      * @return void 
  1439.      * 
  1440.      * @throws ISBN_Exception in case it fails
  1441.      */
  1442.     private function _setGroup($group)
  1443.     {
  1444.         if (is_string($group== false{
  1445.             throw new ISBN_Exception('Wrong Vartype');
  1446.         }
  1447.         $l strlen($group);
  1448.         if ($l || $l 5{
  1449.             throw new ISBN_Exception('Wrong Group Length (' $l ')');
  1450.         }
  1451.         $testbody  substr($group '000000000'09);
  1452.         $testgroup self::_extractGroup($testbody);
  1453.         if ($testgroup === false {
  1454.             throw new ISBN_Exception('Invalid Group');
  1455.         }
  1456.         if ($testgroup != $group{
  1457.             throw new ISBN_Exception('Invalid Group');
  1458.         }        
  1459.         $this->isbn_group $group;
  1460.     }
  1461.  
  1462.     // {{{ getISBN()
  1463.         /**
  1464.      * Get whole ISBN Number
  1465.      *
  1466.      * @return string ISBN Number (unformatted); empty string if this is
  1467.      *                 not a valid ISBN
  1468.      */
  1469.     public function getISBN()
  1470.     {
  1471.         $ver $this->getVersion();
  1472.         if ($ver === false {
  1473.             return '';
  1474.         }
  1475.  
  1476.         $isbn '';
  1477.  
  1478.         $r self::_isbnVersionIsValid($ver);
  1479.         if ($r === false {
  1480.             return $isbn;
  1481.         }
  1482.  
  1483.         $isbn .= $this->getEAN();
  1484.         $isbn .= $this->_getISBNBody();
  1485.         $isbn .= $this->getCheckdigit();
  1486.  
  1487.         return $isbn;
  1488.     }
  1489.     // }}}
  1490.  
  1491.     // {{{ setISBN()
  1492.         /**
  1493.      * Setter for ISBN
  1494.      *
  1495.      * @param string $isbn ISBN Number
  1496.      *              this is a valid ISBN Number or it is an Empty string
  1497.      *              which will reset the class
  1498.      * 
  1499.      * @return void 
  1500.      * 
  1501.      * @throws ISBN_Exception in case it fails
  1502.      * 
  1503.      */
  1504.     public function setISBN($isbn)
  1505.     {
  1506.         if ($isbn == ''{
  1507.             $this->ver ISBN_VERSION_NONE;
  1508.             $this->isbn_group '';
  1509.             $this->isbn_publisher '';
  1510.             $this->isbn_title '';
  1511.         else {
  1512.             $isbnn self::_normaliseISBN($isbn);
  1513.             $ver   self::_getVersion($isbnn);
  1514.             if ($ver === false{
  1515.                 throw new ISBN_Exception('Invalid ISBN');
  1516.             }
  1517.             if ($ver != $this->ver and $this->ver !== ISBN_VERSION_NONE{
  1518.                 throw new ISBN_Exception(
  1519.                   'ISBN Version of passed ISBN (' $ver ') '.
  1520.                   'does not match existing (' $this->ver ').'
  1521.                 );
  1522.             elseif ($this->ver === ISBN_VERSION_NONE{
  1523.                 $this->ver $ver;
  1524.             }
  1525.             $body self::_extractISBNBody($isbnn);
  1526.             if ($body === false{
  1527.                 throw new ISBN_Exception('Invalid ISBN (could not extract body)');
  1528.             }
  1529.             try {
  1530.                 $this->_setISBNBody($body);
  1531.             catch (ISBN_Exception $e{
  1532.                 throw new ISBN_Exception(
  1533.                     'Invalid ISBN (invalid body "' $body '")'$e
  1534.                 );
  1535.             }
  1536.         }
  1537.     }
  1538.     // }}}
  1539.  
  1540.     // {{{ _getISBNBody()
  1541.         /**
  1542.      * _getISBNBody()
  1543.      *
  1544.      * @return string ISBN Body (not an offical term)
  1545.      */
  1546.     private function _getISBNBody()
  1547.     {
  1548.         $body  '';
  1549.         $body .= $this->getGroup();
  1550.         $body .= $this->_getISBNSubbody();
  1551.         return $body;
  1552.     }
  1553.     // }}}
  1554.  
  1555.     // {{{ _setISBNBody()
  1556.         /**
  1557.      * _setISBNBody()
  1558.      *
  1559.      * Setter for ISBNBody
  1560.      *
  1561.      * @param string $body ISBNBody
  1562.      * 
  1563.      * @return void 
  1564.      * 
  1565.      * @throws ISBN_Exception in case it fails
  1566.      */
  1567.     private function _setISBNBody($body)
  1568.     {
  1569.         /* validate parameter */
  1570.         if (is_string($body== false{
  1571.             throw new ISBN_Exception('Not a Body: wrong variabletype');
  1572.         }
  1573.         if (strlen($body!= 9{
  1574.             throw new ISBN_Exception('Not a Body: wrong body length');
  1575.         }
  1576.         if (ctype_digit($body!== true{
  1577.             throw new ISBN_Exception('Not a Body: syntactically not a body');
  1578.         }
  1579.  
  1580.         /* validate body by extracting and validating parts */
  1581.         $group   false;
  1582.         $subbody false;
  1583.  
  1584.         $r self::_isbnBodyParts($body$group$subbody);
  1585.         if ($r == false{
  1586.             throw new ISBN_Exception('Invalid Body');
  1587.         }
  1588.  
  1589.         try {
  1590.             $this->_setGroup($group);
  1591.         catch (ISBN_Exception $e{
  1592.             throw new Exception('Invalid Body: Group is invalid'$e);
  1593.         }
  1594.  
  1595.         try {
  1596.             $this->_setISBNSubbody($subbody);
  1597.         catch (ISBN_Exception $e{
  1598.             throw new ISBN_Exception('Invalid Body: Subbody is invalid'$e);
  1599.         }
  1600.     }
  1601.     // }}}
  1602.  
  1603.     // {{{ _getISBNSubbody()
  1604.         /**
  1605.      * Get ISBNSubbody ()
  1606.      *
  1607.      * @return ISBN Subbody
  1608.      */
  1609.     private function _getISBNSubbody()
  1610.     {
  1611.         $subbody  '';
  1612.         $subbody .= $this->getPublisher();
  1613.         $subbody .= $this->getTitle();
  1614.         return $subbody;
  1615.     }
  1616.     // }}}
  1617.  
  1618.     // {{{ _setISBNSubbody()
  1619.         /**
  1620.      * _setISBNSubbody
  1621.      *
  1622.      * Setter for the ISBN Subbody
  1623.      *
  1624.      * @param string $subbody ISBN Subbody
  1625.      * 
  1626.      * @return void 
  1627.      * 
  1628.      * @throws ISBN_Exception in case it fails
  1629.      */
  1630.     private function _setISBNSubbody($subbody)
  1631.     {
  1632.         /* validate parameter */
  1633.         if (is_string($subbody== false{
  1634.             throw new ISBN_Exception('Wrong Vartype');
  1635.         }
  1636.         $l strlen($subbody);
  1637.         if $l || $l 8{
  1638.             throw new ISBN_Exception('Not a Subbody by length');
  1639.         }
  1640.         /* validate by setting apart */
  1641.         $registrant  false;
  1642.         $publication false;
  1643.         $groupid     intval($this->isbn_group);
  1644.  
  1645.         $r self::_isbnSubbodyParts($subbody$groupid$registrant$publication);
  1646.         if ($r === false{
  1647.             throw new ISBN_Exception('Invalid Subbody');
  1648.         }
  1649.         /* edit+ setter/getter for Registrant/Publisher and Title/Publication */
  1650.         $this->isbn_publisher $registrant;
  1651.         $this->isbn_title $publication;
  1652.     }
  1653.  
  1654.     // {{{ getPublisher()
  1655.         /**
  1656.      * Get the Publication Part of the ISBN Number
  1657.      *
  1658.      * @return string|falsePublisher or false if failed
  1659.      */
  1660.     public function getPublisher()
  1661.     {
  1662.         return $this->isbn_publisher;
  1663.     }
  1664.     // }}}
  1665.  
  1666.     // {{{ getTitle()
  1667.         /**
  1668.      * Get the Title Part of the ISBN Number
  1669.      *
  1670.      * @return string|falseTitle or false if failed
  1671.      */
  1672.     public function getTitle()
  1673.     {
  1674.         return $this->isbn_title;
  1675.     }
  1676.     // }}}
  1677.  
  1678.  
  1679.     // {{{ isValid()
  1680.         /**
  1681.      * Returns this ISBN validity
  1682.      *
  1683.      * @return boolean 
  1684.      */
  1685.     public function isValid()
  1686.     {
  1687.         $isbn $this->getISBN();
  1688.         $r    self::validate($this->getISBN()$this->getVersion());
  1689.         return (bool) $r;
  1690.     }
  1691.  
  1692.     // {{{ validate()
  1693.         /**
  1694.      * Validates an ISBN
  1695.      * 
  1696.      * @param string  $isbn ISBN to validate
  1697.      * @param integer $ver  ISBN-Version to validate against
  1698.      *
  1699.      * @return integer|false   Version value of a valid ISBN or false
  1700.      *                           if it did not validate
  1701.      */
  1702.     public static function validate($isbn$ver ISBN_DEFAULT_INPUTVERSION)
  1703.     {
  1704.         $r self::_isbnVersionIs($ver);
  1705.         if ($r === false{
  1706.             return false;
  1707.         }
  1708.         if ($ver === ISBN_VERSION_UNKNOWN{
  1709.             $ver self::_isbnVersionGuess($isbn);
  1710.         }
  1711.         if (self::_isbnVersionIsValid($ver=== false{
  1712.             return false;
  1713.         }
  1714.         $r self::_isIsbnValid($isbn$ver);
  1715.         if ($r === false{
  1716.             return false;
  1717.         }
  1718.         return $ver;
  1719.     }
  1720.     // }}}
  1721.  
  1722.     // {{{ getVersion()
  1723.         /**
  1724.      * Returns version of this objects ISBN
  1725.      *
  1726.      * @return integer|false Version value or ISBN_VERSION_NONE
  1727.      */
  1728.     public function getVersion()
  1729.     {
  1730.         return $this->ver;
  1731.     }
  1732.  
  1733.  
  1734.     // {{{ guessVersion()
  1735.         /**
  1736.      * Guesses ISBN version of passed string
  1737.      *
  1738.      * Note: This is not Validation. To get the validated
  1739.      * version of an ISBN Number use self::validate();
  1740.      *     
  1741.      * @param string $isbn ISBN Number to guess Version of
  1742.      * 
  1743.      * @return integer|false   Version Value or false if failed
  1744.      * 
  1745.      * @see validate();
  1746.      */
  1747.     public static function guessVersion($isbn)
  1748.     {
  1749.         $r self::_isbnVersionGuess($isbn);
  1750.         return $r;
  1751.     }
  1752.     // }}}
  1753.  
  1754. }
  1755. ?>

Documentation generated on Fri, 19 Jan 2007 13:42:27 +0100 by phpDocumentor 1.3.1