Bootswatch, Summernote, and Captcheck mods for Mods for HESK (mods-for-hesk.com). In use at support.netsyms.com.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

posting_functions.inc.php 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. /**
  3. *
  4. * This file is part of HESK - PHP Help Desk Software.
  5. *
  6. * (c) Copyright Klemen Stirn. All rights reserved.
  7. * https://www.hesk.com
  8. *
  9. * For the full copyright and license agreement information visit
  10. * https://www.hesk.com/eula.php
  11. *
  12. */
  13. /* Check if this is a valid include */
  14. if (!defined('IN_SCRIPT')) {
  15. die('Invalid attempt');
  16. }
  17. /*** FUNCTIONS ***/
  18. function hesk_newTicket($ticket, $isVerified = true)
  19. {
  20. global $hesk_settings, $hesklang, $hesk_db_link;
  21. // Generate a subject if necessary
  22. if (strlen($ticket['subject']) < 1)
  23. {
  24. $ticket['subject'] = sprintf($hesklang['default_subject'], $ticket['name']);
  25. }
  26. // If language is not set or default, set it to NULL.
  27. if (!isset($ticket['language']) || empty($ticket['language'])) {
  28. $language = (!$hesk_settings['can_sel_lang']) ? HESK_DEFAULT_LANGUAGE : hesk_dbEscape($hesklang['LANGUAGE']);
  29. } else {
  30. $language = $ticket['language'];
  31. }
  32. // Get the default ticket status for new tickets and set it accordingly
  33. $defaultNewTicketRs = hesk_dbQuery("SELECT `ID` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `IsNewTicketStatus` = 1");
  34. $defaultNewTicket = hesk_dbFetchAssoc($defaultNewTicketRs);
  35. $ticket['status'] = $defaultNewTicket['ID'];
  36. $tableName = $isVerified ? 'tickets' : 'stage_tickets';
  37. $ticket['message'] = htmLawed($ticket['message'], array('safe' => 1, 'deny_attribute' => 'style'));
  38. $due_date = 'NULL';
  39. if ($ticket['due_date'] != '') {
  40. $due_date = "'" . hesk_dbEscape($ticket['due_date']) . "'";
  41. }
  42. // Prepare SQL for custom fields
  43. $custom_where = '';
  44. $custom_what = '';
  45. for ($i=1; $i<=50; $i++)
  46. {
  47. $custom_where .= ", `custom{$i}`";
  48. $custom_what .= ", '" . (isset($ticket['custom'.$i]) ? hesk_dbEscape($ticket['custom'.$i]) : '') . "'";
  49. }
  50. // Insert ticket into database
  51. hesk_dbQuery("
  52. INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . $tableName . "`
  53. (
  54. `trackid`,
  55. `name`,
  56. `email`,
  57. `category`,
  58. `priority`,
  59. `subject`,
  60. `message`,
  61. `dt`,
  62. `lastchange`,
  63. `articles`,
  64. `ip`,
  65. `language`,
  66. `openedby`,
  67. `owner`,
  68. `attachments`,
  69. `merged`,
  70. `status`,
  71. `latitude`,
  72. `longitude`,
  73. `html`,
  74. `user_agent`,
  75. `screen_resolution_height`,
  76. `screen_resolution_width`,
  77. `due_date`,
  78. `history`
  79. {$custom_where}
  80. )
  81. VALUES
  82. (
  83. '" . hesk_dbEscape($ticket['trackid']) . "',
  84. '" . hesk_dbEscape($ticket['name']) . "',
  85. '" . hesk_dbEscape($ticket['email']) . "',
  86. '" . intval($ticket['category']) . "',
  87. '" . intval($ticket['priority']) . "',
  88. '" . hesk_dbEscape($ticket['subject']) . "',
  89. '" . hesk_dbEscape($ticket['message']) . "',
  90. NOW(),
  91. NOW(),
  92. " . (isset($ticket['articles']) ? "'{$ticket['articles']}'" : 'NULL') . ",
  93. '" . hesk_dbEscape(hesk_getClientIP()) . "',
  94. '" . hesk_dbEscape($language) . "',
  95. '" . (isset($ticket['openedby']) ? intval($ticket['openedby']) : 0) . "',
  96. '" . intval($ticket['owner']) . "',
  97. '" . hesk_dbEscape($ticket['attachments']) . "',
  98. '',
  99. '" . intval($ticket['status']) . "',
  100. '" . hesk_dbEscape($ticket['latitude']) . "',
  101. '" . hesk_dbEscape($ticket['longitude']) . "',
  102. '" . hesk_dbEscape($ticket['html']) . "',
  103. '" . hesk_dbEscape($ticket['user_agent']) . "',
  104. " . hesk_dbEscape($ticket['screen_resolution_height']) . ",
  105. " . hesk_dbEscape($ticket['screen_resolution_width']) . ",
  106. {$due_date},
  107. '" . hesk_dbEscape($ticket['history']) . "'
  108. {$custom_what}
  109. )
  110. ");
  111. // Generate the array with ticket info that can be used in emails
  112. $info = array(
  113. 'email' => $ticket['email'],
  114. 'category' => $ticket['category'],
  115. 'priority' => $ticket['priority'],
  116. 'owner' => $ticket['owner'],
  117. 'trackid' => $ticket['trackid'],
  118. 'status' => $ticket['status'],
  119. 'name' => $ticket['name'],
  120. 'lastreplier' => $ticket['name'],
  121. 'subject' => $ticket['subject'],
  122. 'message' => $ticket['message'],
  123. 'attachments' => $ticket['attachments'],
  124. 'dt' => hesk_date(),
  125. 'lastchange' => hesk_date(),
  126. 'id' => hesk_dbInsertID(),
  127. 'language' => $language,
  128. 'html' => $ticket['html'],
  129. 'due_date' => $ticket['due_date']
  130. );
  131. // Add custom fields to the array
  132. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  133. $info[$k] = $v['use'] ? $ticket[$k] : '';
  134. }
  135. return hesk_ticketToPlain($info, 1);
  136. } // END hesk_newTicket()
  137. function hesk_cleanFileName($filename)
  138. {
  139. $parts = pathinfo($filename);
  140. if (isset($parts['filename'])) {
  141. $filename = $parts['filename'];
  142. } // PHP < 5.2 needs special care
  143. elseif (version_compare(PHP_VERSION, '5.2', '<')) {
  144. $filename = rtrim(str_ireplace($parts['extension'], '', $filename), '.');
  145. } else {
  146. $filename = '';
  147. }
  148. $filename = str_replace(array('%20', '+'), '-', $filename);
  149. $filename = preg_replace('/[\s-]+/', '-', $filename);
  150. $filename = remove_accents($filename);
  151. $filename = preg_replace('/[^A-Za-z0-9\.\-_]/', '', $filename);
  152. $filename = trim($filename, '-_');
  153. if (strlen($filename) < 1 || strpos($filename, '.') === 0) {
  154. $filename = mt_rand(10000, 99999) . $filename;
  155. }
  156. return $filename . '.' . $parts['extension'];
  157. } // END hesk_cleanFileName()
  158. function hesk_getCategoryPriority($id)
  159. {
  160. global $hesk_settings, $hesklang, $hesk_db_link;
  161. $priority = 3;
  162. // Does the category have a different default priority?
  163. $res = hesk_dbQuery("SELECT `priority` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`=" . intval($id) . " LIMIT 1");
  164. if (hesk_dbNumRows($res) == 1) {
  165. $priority = hesk_dbResult($res);
  166. }
  167. return $priority;
  168. } // END hesk_getCategoryPriority()
  169. function hesk_verifyCategory($any_type = 0)
  170. {
  171. global $hesk_settings, $hesklang, $hesk_db_link, $hesk_error_buffer, $tmpvar;
  172. // Verify just by public or any category type?
  173. $type = $any_type ? " 1 " : " `type`='0' ";
  174. // Does the category exist?
  175. $res = hesk_dbQuery("SELECT `name`, `autoassign` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`='" . $tmpvar['category'] . "' AND {$type} LIMIT 1");
  176. if (hesk_dbNumRows($res) == 1) {
  177. $hesk_settings['category_data'][$tmpvar['category']] = hesk_dbFetchAssoc($res);
  178. return true;
  179. }
  180. // OK, something wrong with the category. Get a list of categories to check few things
  181. $res = hesk_dbQuery("SELECT `id`, `name`, `autoassign` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE {$type} ORDER BY `id` ASC");
  182. $num = hesk_dbNumRows($res);
  183. // If more than 1 choice is available, let the user choose
  184. if ($num > 1) {
  185. $hesk_error_buffer['category'] = $hesklang['sel_app_cat'];
  186. return false;
  187. } // Exactly one category is available, use it
  188. elseif ($num == 1) {
  189. $tmp = hesk_dbFetchAssoc($res);
  190. $tmpvar['category'] = $tmp['id'];
  191. $hesk_settings['category_data'][$tmpvar['category']] = $tmp;
  192. return true;
  193. } // No category is available, use the first one we find (should be ID 1)
  194. else {
  195. $res = hesk_dbQuery("SELECT `id`, `name`, `autoassign` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` ORDER BY `id` ASC LIMIT 1");
  196. if (hesk_dbNumRows($res) == 1) {
  197. $tmp = hesk_dbFetchAssoc($res);
  198. $tmpvar['category'] = $tmp['id'];
  199. $hesk_settings['category_data'][$tmpvar['category']] = $tmp;
  200. } else {
  201. // What the ...? No categories exist??? You know what, just error out...
  202. hesk_error($hesklang['int_error'] . ': ' . $hesklang['cat_not_found']);
  203. }
  204. }
  205. } // END hesk_verifyCategory()
  206. // The following code has been borrowed from Wordpress
  207. // Credits: http://wordpress.org
  208. function remove_accents($string)
  209. {
  210. if (!preg_match('/[\x80-\xff]/', $string))
  211. return $string;
  212. if (seems_utf8($string)) {
  213. $chars = array(
  214. // Decompositions for Latin-1 Supplement
  215. chr(194) . chr(170) => 'a', chr(194) . chr(186) => 'o',
  216. chr(195) . chr(128) => 'A', chr(195) . chr(129) => 'A',
  217. chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A',
  218. chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A',
  219. chr(195) . chr(134) => 'AE', chr(195) . chr(135) => 'C',
  220. chr(195) . chr(136) => 'E', chr(195) . chr(137) => 'E',
  221. chr(195) . chr(138) => 'E', chr(195) . chr(139) => 'E',
  222. chr(195) . chr(140) => 'I', chr(195) . chr(141) => 'I',
  223. chr(195) . chr(142) => 'I', chr(195) . chr(143) => 'I',
  224. chr(195) . chr(144) => 'D', chr(195) . chr(145) => 'N',
  225. chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O',
  226. chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O',
  227. chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U',
  228. chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U',
  229. chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y',
  230. chr(195) . chr(158) => 'TH', chr(195) . chr(159) => 's',
  231. chr(195) . chr(160) => 'a', chr(195) . chr(161) => 'a',
  232. chr(195) . chr(162) => 'a', chr(195) . chr(163) => 'a',
  233. chr(195) . chr(164) => 'a', chr(195) . chr(165) => 'a',
  234. chr(195) . chr(166) => 'ae', chr(195) . chr(167) => 'c',
  235. chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e',
  236. chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e',
  237. chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i',
  238. chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i',
  239. chr(195) . chr(176) => 'd', chr(195) . chr(177) => 'n',
  240. chr(195) . chr(178) => 'o', chr(195) . chr(179) => 'o',
  241. chr(195) . chr(180) => 'o', chr(195) . chr(181) => 'o',
  242. chr(195) . chr(182) => 'o', chr(195) . chr(184) => 'o',
  243. chr(195) . chr(185) => 'u', chr(195) . chr(186) => 'u',
  244. chr(195) . chr(187) => 'u', chr(195) . chr(188) => 'u',
  245. chr(195) . chr(189) => 'y', chr(195) . chr(190) => 'th',
  246. chr(195) . chr(191) => 'y', chr(195) . chr(152) => 'O',
  247. // Decompositions for Latin Extended-A
  248. chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a',
  249. chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a',
  250. chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a',
  251. chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c',
  252. chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c',
  253. chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c',
  254. chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c',
  255. chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd',
  256. chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd',
  257. chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e',
  258. chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e',
  259. chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e',
  260. chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e',
  261. chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e',
  262. chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g',
  263. chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g',
  264. chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g',
  265. chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g',
  266. chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h',
  267. chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h',
  268. chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i',
  269. chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i',
  270. chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i',
  271. chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i',
  272. chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i',
  273. chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij',
  274. chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j',
  275. chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k',
  276. chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L',
  277. chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L',
  278. chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L',
  279. chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L',
  280. chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L',
  281. chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N',
  282. chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N',
  283. chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N',
  284. chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N',
  285. chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N',
  286. chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o',
  287. chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o',
  288. chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o',
  289. chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe',
  290. chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r',
  291. chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r',
  292. chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r',
  293. chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's',
  294. chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's',
  295. chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's',
  296. chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's',
  297. chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't',
  298. chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't',
  299. chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't',
  300. chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u',
  301. chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u',
  302. chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u',
  303. chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u',
  304. chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u',
  305. chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u',
  306. chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w',
  307. chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y',
  308. chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z',
  309. chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z',
  310. chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z',
  311. chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's',
  312. // Decompositions for Latin Extended-B
  313. chr(200) . chr(152) => 'S', chr(200) . chr(153) => 's',
  314. chr(200) . chr(154) => 'T', chr(200) . chr(155) => 't',
  315. // Euro Sign
  316. chr(226) . chr(130) . chr(172) => 'E',
  317. // GBP (Pound) Sign
  318. chr(194) . chr(163) => '',
  319. // Vowels with diacritic (Vietnamese)
  320. // unmarked
  321. chr(198) . chr(160) => 'O', chr(198) . chr(161) => 'o',
  322. chr(198) . chr(175) => 'U', chr(198) . chr(176) => 'u',
  323. // grave accent
  324. chr(225) . chr(186) . chr(166) => 'A', chr(225) . chr(186) . chr(167) => 'a',
  325. chr(225) . chr(186) . chr(176) => 'A', chr(225) . chr(186) . chr(177) => 'a',
  326. chr(225) . chr(187) . chr(128) => 'E', chr(225) . chr(187) . chr(129) => 'e',
  327. chr(225) . chr(187) . chr(146) => 'O', chr(225) . chr(187) . chr(147) => 'o',
  328. chr(225) . chr(187) . chr(156) => 'O', chr(225) . chr(187) . chr(157) => 'o',
  329. chr(225) . chr(187) . chr(170) => 'U', chr(225) . chr(187) . chr(171) => 'u',
  330. chr(225) . chr(187) . chr(178) => 'Y', chr(225) . chr(187) . chr(179) => 'y',
  331. // hook
  332. chr(225) . chr(186) . chr(162) => 'A', chr(225) . chr(186) . chr(163) => 'a',
  333. chr(225) . chr(186) . chr(168) => 'A', chr(225) . chr(186) . chr(169) => 'a',
  334. chr(225) . chr(186) . chr(178) => 'A', chr(225) . chr(186) . chr(179) => 'a',
  335. chr(225) . chr(186) . chr(186) => 'E', chr(225) . chr(186) . chr(187) => 'e',
  336. chr(225) . chr(187) . chr(130) => 'E', chr(225) . chr(187) . chr(131) => 'e',
  337. chr(225) . chr(187) . chr(136) => 'I', chr(225) . chr(187) . chr(137) => 'i',
  338. chr(225) . chr(187) . chr(142) => 'O', chr(225) . chr(187) . chr(143) => 'o',
  339. chr(225) . chr(187) . chr(148) => 'O', chr(225) . chr(187) . chr(149) => 'o',
  340. chr(225) . chr(187) . chr(158) => 'O', chr(225) . chr(187) . chr(159) => 'o',
  341. chr(225) . chr(187) . chr(166) => 'U', chr(225) . chr(187) . chr(167) => 'u',
  342. chr(225) . chr(187) . chr(172) => 'U', chr(225) . chr(187) . chr(173) => 'u',
  343. chr(225) . chr(187) . chr(182) => 'Y', chr(225) . chr(187) . chr(183) => 'y',
  344. // tilde
  345. chr(225) . chr(186) . chr(170) => 'A', chr(225) . chr(186) . chr(171) => 'a',
  346. chr(225) . chr(186) . chr(180) => 'A', chr(225) . chr(186) . chr(181) => 'a',
  347. chr(225) . chr(186) . chr(188) => 'E', chr(225) . chr(186) . chr(189) => 'e',
  348. chr(225) . chr(187) . chr(132) => 'E', chr(225) . chr(187) . chr(133) => 'e',
  349. chr(225) . chr(187) . chr(150) => 'O', chr(225) . chr(187) . chr(151) => 'o',
  350. chr(225) . chr(187) . chr(160) => 'O', chr(225) . chr(187) . chr(161) => 'o',
  351. chr(225) . chr(187) . chr(174) => 'U', chr(225) . chr(187) . chr(175) => 'u',
  352. chr(225) . chr(187) . chr(184) => 'Y', chr(225) . chr(187) . chr(185) => 'y',
  353. // acute accent
  354. chr(225) . chr(186) . chr(164) => 'A', chr(225) . chr(186) . chr(165) => 'a',
  355. chr(225) . chr(186) . chr(174) => 'A', chr(225) . chr(186) . chr(175) => 'a',
  356. chr(225) . chr(186) . chr(190) => 'E', chr(225) . chr(186) . chr(191) => 'e',
  357. chr(225) . chr(187) . chr(144) => 'O', chr(225) . chr(187) . chr(145) => 'o',
  358. chr(225) . chr(187) . chr(154) => 'O', chr(225) . chr(187) . chr(155) => 'o',
  359. chr(225) . chr(187) . chr(168) => 'U', chr(225) . chr(187) . chr(169) => 'u',
  360. // dot below
  361. chr(225) . chr(186) . chr(160) => 'A', chr(225) . chr(186) . chr(161) => 'a',
  362. chr(225) . chr(186) . chr(172) => 'A', chr(225) . chr(186) . chr(173) => 'a',
  363. chr(225) . chr(186) . chr(182) => 'A', chr(225) . chr(186) . chr(183) => 'a',
  364. chr(225) . chr(186) . chr(184) => 'E', chr(225) . chr(186) . chr(185) => 'e',
  365. chr(225) . chr(187) . chr(134) => 'E', chr(225) . chr(187) . chr(135) => 'e',
  366. chr(225) . chr(187) . chr(138) => 'I', chr(225) . chr(187) . chr(139) => 'i',
  367. chr(225) . chr(187) . chr(140) => 'O', chr(225) . chr(187) . chr(141) => 'o',
  368. chr(225) . chr(187) . chr(152) => 'O', chr(225) . chr(187) . chr(153) => 'o',
  369. chr(225) . chr(187) . chr(162) => 'O', chr(225) . chr(187) . chr(163) => 'o',
  370. chr(225) . chr(187) . chr(164) => 'U', chr(225) . chr(187) . chr(165) => 'u',
  371. chr(225) . chr(187) . chr(176) => 'U', chr(225) . chr(187) . chr(177) => 'u',
  372. chr(225) . chr(187) . chr(180) => 'Y', chr(225) . chr(187) . chr(181) => 'y',
  373. // Vowels with diacritic (Chinese, Hanyu Pinyin)
  374. chr(201) . chr(145) => 'a',
  375. // macron
  376. chr(199) . chr(149) => 'U', chr(199) . chr(150) => 'u',
  377. // acute accent
  378. chr(199) . chr(151) => 'U', chr(199) . chr(152) => 'u',
  379. // caron
  380. chr(199) . chr(141) => 'A', chr(199) . chr(142) => 'a',
  381. chr(199) . chr(143) => 'I', chr(199) . chr(144) => 'i',
  382. chr(199) . chr(145) => 'O', chr(199) . chr(146) => 'o',
  383. chr(199) . chr(147) => 'U', chr(199) . chr(148) => 'u',
  384. chr(199) . chr(153) => 'U', chr(199) . chr(154) => 'u',
  385. // grave accent
  386. chr(199) . chr(155) => 'U', chr(199) . chr(156) => 'u',
  387. );
  388. $string = strtr($string, $chars);
  389. } else {
  390. // Assume ISO-8859-1 if not UTF-8
  391. $chars['in'] = chr(128) . chr(131) . chr(138) . chr(142) . chr(154) . chr(158)
  392. . chr(159) . chr(162) . chr(165) . chr(181) . chr(192) . chr(193) . chr(194)
  393. . chr(195) . chr(196) . chr(197) . chr(199) . chr(200) . chr(201) . chr(202)
  394. . chr(203) . chr(204) . chr(205) . chr(206) . chr(207) . chr(209) . chr(210)
  395. . chr(211) . chr(212) . chr(213) . chr(214) . chr(216) . chr(217) . chr(218)
  396. . chr(219) . chr(220) . chr(221) . chr(224) . chr(225) . chr(226) . chr(227)
  397. . chr(228) . chr(229) . chr(231) . chr(232) . chr(233) . chr(234) . chr(235)
  398. . chr(236) . chr(237) . chr(238) . chr(239) . chr(241) . chr(242) . chr(243)
  399. . chr(244) . chr(245) . chr(246) . chr(248) . chr(249) . chr(250) . chr(251)
  400. . chr(252) . chr(253) . chr(255);
  401. $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
  402. $string = strtr($string, $chars['in'], $chars['out']);
  403. $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
  404. $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
  405. $string = str_replace($double_chars['in'], $double_chars['out'], $string);
  406. }
  407. return $string;
  408. }
  409. function seems_utf8($str)
  410. {
  411. $length = strlen($str);
  412. for ($i = 0; $i < $length; $i++) {
  413. $c = ord($str[$i]);
  414. if ($c < 0x80) $n = 0; # 0bbbbbbb
  415. elseif (($c & 0xE0) == 0xC0) $n = 1; # 110bbbbb
  416. elseif (($c & 0xF0) == 0xE0) $n = 2; # 1110bbbb
  417. elseif (($c & 0xF8) == 0xF0) $n = 3; # 11110bbb
  418. elseif (($c & 0xFC) == 0xF8) $n = 4; # 111110bb
  419. elseif (($c & 0xFE) == 0xFC) $n = 5; # 1111110b
  420. else return false; # Does not match any model
  421. for ($j = 0; $j < $n; $j++) { # n bytes matching 10bbbbbb follow ?
  422. if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
  423. return false;
  424. }
  425. }
  426. return true;
  427. }
  428. function utf8_uri_encode($utf8_string, $length = 0)
  429. {
  430. $unicode = '';
  431. $values = array();
  432. $num_octets = 1;
  433. $unicode_length = 0;
  434. $string_length = strlen($utf8_string);
  435. for ($i = 0; $i < $string_length; $i++) {
  436. $value = ord($utf8_string[$i]);
  437. if ($value < 128) {
  438. if ($length && ($unicode_length >= $length))
  439. break;
  440. $unicode .= chr($value);
  441. $unicode_length++;
  442. } else {
  443. if (count($values) == 0) $num_octets = ($value < 224) ? 2 : 3;
  444. $values[] = $value;
  445. if ($length && ($unicode_length + ($num_octets * 3)) > $length)
  446. break;
  447. if (count($values) == $num_octets) {
  448. if ($num_octets == 3) {
  449. $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
  450. $unicode_length += 9;
  451. } else {
  452. $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
  453. $unicode_length += 6;
  454. }
  455. $values = array();
  456. $num_octets = 1;
  457. }
  458. }
  459. }
  460. return $unicode;
  461. }