ISBN 校驗規則
ISBN-10(2007 年前)
- 前 9 碼加權和:`S = d1×10 + d2×9 + ... + d9×2`
- `M = S % 11`
- `N = 11 - M`
- 校驗碼:`N=10 → 'X'`、`N=11 → '0'`、其他 → `N`
ISBN-13(現行)
- 前 12 碼加權和:奇數位×1、偶數位×3 → `S`
- `M = S % 10`
- `N = 10 - M`
- 校驗碼:`N=10 → '0'`、其他 → `N`
PHP 實作
<?php
/**
* 計算 ISBN 加權和
* @param string $isbn 純數字字串(含校驗碼或不含)
* @param int $len 10 或 13
* @return int
*/
function isbn_weight_sum(string $isbn, int $len): int
{
$sum = 0;
if ($len === 10) {
for ($i = 0; $i < 9; $i++) {
$sum += (int)$isbn[$i] * (10 - $i);
}
} elseif ($len === 13) {
for ($i = 0; $i < 12; $i++) {
$sum += (int)$isbn[$i] * ($i % 2 === 0 ? 1 : 3);
}
}
return $sum;
}
/**
* 計算校驗碼
* @return string 校驗碼字元
*/
function isbn_check_digit(string $isbn, int $len): string
{
if ($len === 10) {
$digit = 11 - (isbn_weight_sum($isbn, 10) % 11);
if ($digit === 10) return 'X';
if ($digit === 11) return '0';
return (string)$digit;
}
if ($len === 13) {
$digit = 10 - (isbn_weight_sum($isbn, 13) % 10);
if ($digit === 10) return '0';
return (string)$digit;
}
throw new InvalidArgumentException('ISBN length must be 10 or 13');
}
/**
* 驗證 ISBN 合法性
* @param string $isbn 可能含連字號,自動過濾
* @return bool
*/
function is_valid_isbn(string $isbn): bool
{
$clean = str_replace(['-', ' '], '', $isbn);
$len = strlen($clean);
if ($len !== 10 && $len !== 13) return false;
$check = isbn_check_digit($clean, $len);
return $clean[$len - 1] === $check;
}
// 使用
var_dump(is_valid_isbn('978-7-5074-2178-1')); // true
var_dump(is_valid_isbn('7-309-04547-5')); // true
var_dump(is_valid_isbn('9787507421780')); // false (校驗碼錯誤)
擴充應用
- **ISBN-10 轉 ISBN-13**:前綴 `978` + 前 9 碼 + 重新計算 ISBN-13 校驗碼。
- **批次驗證**:讀取 CSV/Excel,輸出合法/不合法清單。
- **前端即時驗證**:同演算法移植 JS,使用者輸入時即時提示。
注意事項
- 輸入可能含連字號/空格,驗證前先 `str_replace(['-',' '], '', $isbn)`。
- ISBN-10 校驗碼可能為 `X`(大寫),比較時需大小寫一致。
- 此函式僅驗證**格式合法性**,不保證該 ISBN 確已出版(需查詢 ISBN 資料庫)。