validator.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*!
  2. * Copyright (c) 2014 Chris O'Hara <cohara87@gmail.com>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files (the
  6. * "Software"), to deal in the Software without restriction, including
  7. * without limitation the rights to use, copy, modify, merge, publish,
  8. * distribute, sublicense, and/or sell copies of the Software, and to
  9. * permit persons to whom the Software is furnished to do so, subject to
  10. * the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. (function (name, definition) {
  24. if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
  25. module.exports = definition();
  26. } else if (typeof define === 'function' && typeof define.amd === 'object') {
  27. define(definition);
  28. } else {
  29. this[name] = definition();
  30. }
  31. })('validator', function (validator) {
  32. 'use strict';
  33. validator = { version: '3.19.1' };
  34. var email = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
  35. var creditCard = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/;
  36. var isbn10Maybe = /^(?:[0-9]{9}X|[0-9]{10})$/
  37. , isbn13Maybe = /^(?:[0-9]{13})$/;
  38. var ipv4Maybe = /^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/
  39. , ipv6 = /^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$/;
  40. var uuid = {
  41. '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i
  42. , '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  43. , '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
  44. , all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i
  45. };
  46. var alpha = /^[a-zA-Z]+$/
  47. , alphanumeric = /^[a-zA-Z0-9]+$/
  48. , numeric = /^-?[0-9]+$/
  49. , int = /^(?:-?(?:0|[1-9][0-9]*))$/
  50. , float = /^(?:-?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/
  51. , hexadecimal = /^[0-9a-fA-F]+$/
  52. , hexcolor = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
  53. var ascii = /^[\x00-\x7F]+$/
  54. , multibyte = /[^\x00-\x7F]/
  55. , fullWidth = /[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/
  56. , halfWidth = /[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]/;
  57. var surrogatePair = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
  58. var base64 = /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/;
  59. validator.extend = function (name, fn) {
  60. validator[name] = function () {
  61. var args = Array.prototype.slice.call(arguments);
  62. args[0] = validator.toString(args[0]);
  63. return fn.apply(validator, args);
  64. };
  65. };
  66. //Right before exporting the validator object, pass each of the builtins
  67. //through extend() so that their first argument is coerced to a string
  68. validator.init = function () {
  69. for (var name in validator) {
  70. if (typeof validator[name] !== 'function' || name === 'toString' ||
  71. name === 'toDate' || name === 'extend' || name === 'init') {
  72. continue;
  73. }
  74. validator.extend(name, validator[name]);
  75. }
  76. };
  77. validator.toString = function (input) {
  78. if (typeof input === 'object' && input !== null && input.toString) {
  79. input = input.toString();
  80. } else if (input === null || typeof input === 'undefined' || (isNaN(input) && !input.length)) {
  81. input = '';
  82. } else if (typeof input !== 'string') {
  83. input += '';
  84. }
  85. return input;
  86. };
  87. validator.toDate = function (date) {
  88. if (Object.prototype.toString.call(date) === '[object Date]') {
  89. return date;
  90. }
  91. date = Date.parse(date);
  92. return !isNaN(date) ? new Date(date) : null;
  93. };
  94. validator.toFloat = function (str) {
  95. return parseFloat(str);
  96. };
  97. validator.toInt = function (str, radix) {
  98. return parseInt(str, radix || 10);
  99. };
  100. validator.toBoolean = function (str, strict) {
  101. if (strict) {
  102. return str === '1' || str === 'true';
  103. }
  104. return str !== '0' && str !== 'false' && str !== '';
  105. };
  106. validator.equals = function (str, comparison) {
  107. return str === validator.toString(comparison);
  108. };
  109. validator.contains = function (str, elem) {
  110. return str.indexOf(validator.toString(elem)) >= 0;
  111. };
  112. validator.matches = function (str, pattern, modifiers) {
  113. if (Object.prototype.toString.call(pattern) !== '[object RegExp]') {
  114. pattern = new RegExp(pattern, modifiers);
  115. }
  116. return pattern.test(str);
  117. };
  118. validator.isEmail = function (str) {
  119. return email.test(str);
  120. };
  121. var default_url_options = {
  122. protocols: [ 'http', 'https', 'ftp' ]
  123. , require_tld: true
  124. , require_protocol: false
  125. , allow_underscores: false
  126. };
  127. validator.isURL = function (str, options) {
  128. if (!str || str.length >= 2083) {
  129. return false;
  130. }
  131. options = merge(options, default_url_options);
  132. var ipv4_url_parts = [
  133. '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])'
  134. , '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}',
  135. , '(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))'
  136. ];
  137. var protocol = '(?:(?:' + options.protocols.join('|') + ')://)' + (options.require_protocol ? '' : '?')
  138. , auth = '(?:\\S+(?::\\S*)?@)?'
  139. , ipv4 = '(?:' + ipv4_url_parts.join('') + ')'
  140. , hostname = '(' + ipv4 + '|' + domain(options) + '|localhost)'
  141. , port = '(\\d{1,5})'
  142. , host = hostname + '(?::' + port + ')?'
  143. , path_query_anchor = '(?:(?:/|\\?|#)[^\\s]*)?';
  144. var is_url = new RegExp('^(?!mailto:)' + protocol + auth + host + path_query_anchor + '$', 'i')
  145. , match = str.match(is_url);
  146. if (!match) {
  147. return false;
  148. }
  149. host = match[1];
  150. port = match[2];
  151. if (port && !(port > 0 && port <= 65535)) {
  152. return false;
  153. }
  154. if (options.host_whitelist && options.host_whitelist.indexOf(host) === -1) {
  155. return false;
  156. }
  157. if (options.host_blacklist && options.host_blacklist.indexOf(host) !== -1) {
  158. return false;
  159. }
  160. return true;
  161. };
  162. validator.isIP = function (str, version) {
  163. version = validator.toString(version);
  164. if (!version) {
  165. return validator.isIP(str, 4) || validator.isIP(str, 6);
  166. } else if (version === '4') {
  167. if (!ipv4Maybe.test(str)) {
  168. return false;
  169. }
  170. var parts = str.split('.').sort(function (a, b) {
  171. return a - b;
  172. });
  173. return parts[3] <= 255;
  174. }
  175. return version === '6' && ipv6.test(str);
  176. };
  177. var default_fqdn_options = {
  178. require_tld: true
  179. , allow_underscores: false
  180. };
  181. validator.isFQDN = function (str, options) {
  182. options = merge(options, default_fqdn_options);
  183. return new RegExp('^' + domain(options) + '$', 'i').test(str);
  184. };
  185. validator.isAlpha = function (str) {
  186. return alpha.test(str);
  187. };
  188. validator.isAlphanumeric = function (str) {
  189. return alphanumeric.test(str);
  190. };
  191. validator.isNumeric = function (str) {
  192. return numeric.test(str);
  193. };
  194. validator.isHexadecimal = function (str) {
  195. return hexadecimal.test(str);
  196. };
  197. validator.isHexColor = function (str) {
  198. return hexcolor.test(str);
  199. };
  200. validator.isLowercase = function (str) {
  201. return str === str.toLowerCase();
  202. };
  203. validator.isUppercase = function (str) {
  204. return str === str.toUpperCase();
  205. };
  206. validator.isInt = function (str) {
  207. return int.test(str);
  208. };
  209. validator.isFloat = function (str) {
  210. return str !== '' && float.test(str);
  211. };
  212. validator.isDivisibleBy = function (str, num) {
  213. return validator.toFloat(str) % validator.toInt(num) === 0;
  214. };
  215. validator.isNull = function (str) {
  216. return str.length === 0;
  217. };
  218. validator.isLength = function (str, min, max) {
  219. var surrogatePairs = str.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g) || [];
  220. var len = str.length - surrogatePairs.length;
  221. return len >= min && (typeof max === 'undefined' || len <= max);
  222. };
  223. validator.isByteLength = function (str, min, max) {
  224. return str.length >= min && (typeof max === 'undefined' || str.length <= max);
  225. };
  226. validator.isUUID = function (str, version) {
  227. var pattern = uuid[version ? version : 'all'];
  228. return pattern && pattern.test(str);
  229. };
  230. validator.isDate = function (str) {
  231. return !isNaN(Date.parse(str));
  232. };
  233. validator.isAfter = function (str, date) {
  234. var comparison = validator.toDate(date || new Date())
  235. , original = validator.toDate(str);
  236. return !!(original && comparison && original > comparison);
  237. };
  238. validator.isBefore = function (str, date) {
  239. var comparison = validator.toDate(date || new Date())
  240. , original = validator.toDate(str);
  241. return original && comparison && original < comparison;
  242. };
  243. validator.isIn = function (str, options) {
  244. if (!options || typeof options.indexOf !== 'function') {
  245. return false;
  246. }
  247. if (Object.prototype.toString.call(options) === '[object Array]') {
  248. var array = [];
  249. for (var i = 0, len = options.length; i < len; i++) {
  250. array[i] = validator.toString(options[i]);
  251. }
  252. options = array;
  253. }
  254. return options.indexOf(str) >= 0;
  255. };
  256. validator.isCreditCard = function (str) {
  257. var sanitized = str.replace(/[^0-9]+/g, '');
  258. if (!creditCard.test(sanitized)) {
  259. return false;
  260. }
  261. var sum = 0, digit, tmpNum, shouldDouble;
  262. for (var i = sanitized.length - 1; i >= 0; i--) {
  263. digit = sanitized.substring(i, (i + 1));
  264. tmpNum = parseInt(digit, 10);
  265. if (shouldDouble) {
  266. tmpNum *= 2;
  267. if (tmpNum >= 10) {
  268. sum += ((tmpNum % 10) + 1);
  269. } else {
  270. sum += tmpNum;
  271. }
  272. } else {
  273. sum += tmpNum;
  274. }
  275. shouldDouble = !shouldDouble;
  276. }
  277. return !!((sum % 10) === 0 ? sanitized : false);
  278. };
  279. validator.isISBN = function (str, version) {
  280. version = validator.toString(version);
  281. if (!version) {
  282. return validator.isISBN(str, 10) || validator.isISBN(str, 13);
  283. }
  284. var sanitized = str.replace(/[\s-]+/g, '')
  285. , checksum = 0, i;
  286. if (version === '10') {
  287. if (!isbn10Maybe.test(sanitized)) {
  288. return false;
  289. }
  290. for (i = 0; i < 9; i++) {
  291. checksum += (i + 1) * sanitized.charAt(i);
  292. }
  293. if (sanitized.charAt(9) === 'X') {
  294. checksum += 10 * 10;
  295. } else {
  296. checksum += 10 * sanitized.charAt(9);
  297. }
  298. if ((checksum % 11) === 0) {
  299. return !!sanitized;
  300. }
  301. } else if (version === '13') {
  302. if (!isbn13Maybe.test(sanitized)) {
  303. return false;
  304. }
  305. var factor = [ 1, 3 ];
  306. for (i = 0; i < 12; i++) {
  307. checksum += factor[i % 2] * sanitized.charAt(i);
  308. }
  309. if (sanitized.charAt(12) - ((10 - (checksum % 10)) % 10) === 0) {
  310. return !!sanitized;
  311. }
  312. }
  313. return false;
  314. };
  315. validator.isJSON = function (str) {
  316. try {
  317. JSON.parse(str);
  318. } catch (e) {
  319. return false;
  320. }
  321. return true;
  322. };
  323. validator.isMultibyte = function (str) {
  324. return multibyte.test(str);
  325. };
  326. validator.isAscii = function (str) {
  327. return ascii.test(str);
  328. };
  329. validator.isFullWidth = function (str) {
  330. return fullWidth.test(str);
  331. };
  332. validator.isHalfWidth = function (str) {
  333. return halfWidth.test(str);
  334. };
  335. validator.isVariableWidth = function (str) {
  336. return fullWidth.test(str) && halfWidth.test(str);
  337. };
  338. validator.isSurrogatePair = function (str) {
  339. return surrogatePair.test(str);
  340. };
  341. validator.isBase64 = function (str) {
  342. return base64.test(str);
  343. };
  344. validator.ltrim = function (str, chars) {
  345. var pattern = chars ? new RegExp('^[' + chars + ']+', 'g') : /^\s+/g;
  346. return str.replace(pattern, '');
  347. };
  348. validator.rtrim = function (str, chars) {
  349. var pattern = chars ? new RegExp('[' + chars + ']+$', 'g') : /\s+$/g;
  350. return str.replace(pattern, '');
  351. };
  352. validator.trim = function (str, chars) {
  353. var pattern = chars ? new RegExp('^[' + chars + ']+|[' + chars + ']+$', 'g') : /^\s+|\s+$/g;
  354. return str.replace(pattern, '');
  355. };
  356. validator.escape = function (str) {
  357. return (str.replace(/&/g, '&amp;')
  358. .replace(/"/g, '&quot;')
  359. .replace(/'/g, '&#x27;')
  360. .replace(/</g, '&lt;')
  361. .replace(/>/g, '&gt;'));
  362. };
  363. validator.stripLow = function (str, keep_new_lines) {
  364. var chars = keep_new_lines ? '\x00-\x09\x0B\x0C\x0E-\x1F\x7F' : '\x00-\x1F\x7F';
  365. return validator.blacklist(str, chars);
  366. };
  367. validator.whitelist = function (str, chars) {
  368. return str.replace(new RegExp('[^' + chars + ']+', 'g'), '');
  369. };
  370. validator.blacklist = function (str, chars) {
  371. return str.replace(new RegExp('[' + chars + ']+', 'g'), '');
  372. };
  373. validator.normalizeEmail = function (email) {
  374. var parts = email.toLowerCase().split('@', 2);
  375. if (parts[1] === 'gmail.com' || parts[1] === 'googlemail.com') {
  376. parts[0] = parts[0].replace(/\./g, '').split('+')[0];
  377. email = parts.join('@');
  378. }
  379. return email;
  380. };
  381. function merge(obj, defaults) {
  382. obj = obj || {};
  383. for (var key in defaults) {
  384. if (typeof obj[key] === 'undefined') {
  385. obj[key] = defaults[key];
  386. }
  387. }
  388. return obj;
  389. }
  390. function domain(options) {
  391. var sep = '-?-?' + (options.allow_underscores ? '_?' : '')
  392. , alpha = 'a-z\\u00a1-\\uffff'
  393. , alphanum = alpha + '0-9'
  394. , subdomain = '(?:(?:[' + alphanum + ']+' + sep + ')*[' + alphanum + ']+)'
  395. , tld = '(?:\\.(?:[' + alpha + ']{2,}))' + (options.require_tld ? '' : '?');
  396. return '(?:' + subdomain + '(?:\\.' + subdomain + ')*' + tld + ')';
  397. }
  398. validator.init();
  399. return validator;
  400. });