PageRenderTime 71ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/docroot/wp-content/plugins/zannel-tools/zannel-tools.php

https://bitbucket.org/greg_gallant/cd-blog
PHP | 2736 lines | 2116 code | 250 blank | 370 comment | 329 complexity | 9961694b15d320c208adcde48c7526fe MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0, GPL-2.0, BSD-3-Clause
  1. <?php
  2. /*
  3. Plugin Name: Zannel Tools
  4. Plugin URI: http://zannel.com
  5. Description: A complete integration between your WordPress blog and <a href="http://zannel.com">Zannel</a>. Bring your Zannel Updates into your blog and pass your blog posts back to Zannel.
  6. Version: 1.0
  7. Author: Crowd Favorite
  8. Author URI: http://crowdfavorite.com
  9. Template Tags:
  10. Latest update: <?php cfzt_latest_zupdate(); ?>
  11. List of updates: <?php cfzt_sidebar_zupdates(); ?>
  12. */
  13. // Released under the GPL license
  14. // http://www.opensource.org/licenses/gpl-license.php
  15. //
  16. // This is an add-on for WordPress
  17. // http://wordpress.org/
  18. //
  19. // Based on Twitter Tools by Crowd Favorite, Ltd.
  20. //
  21. // **********************************************************************
  22. // This program is distributed in the hope that it will be useful, but
  23. // WITHOUT ANY WARRANTY; without even the implied warranty of
  24. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  25. // **********************************************************************
  26. load_plugin_textdomain('zannel-tools');
  27. if (!defined('PLUGINDIR')) {
  28. define('PLUGINDIR','wp-content/plugins');
  29. }
  30. if (is_file(trailingslashit(ABSPATH.PLUGINDIR).'zannel-tools.php')) {
  31. define('CFZT_FILE', trailingslashit(ABSPATH.PLUGINDIR).'zannel-tools.php');
  32. }
  33. else if (is_file(trailingslashit(ABSPATH.PLUGINDIR).'zannel-tools/zannel-tools.php')) {
  34. define('CFZT_FILE', trailingslashit(ABSPATH.PLUGINDIR).'zannel-tools/zannel-tools.php');
  35. }
  36. if (!function_exists('is_admin_page')) {
  37. function is_admin_page() {
  38. if (function_exists('is_admin')) {
  39. return is_admin();
  40. }
  41. if (function_exists('check_admin_referer')) {
  42. return true;
  43. }
  44. else {
  45. return false;
  46. }
  47. }
  48. }
  49. if (!function_exists('wp_prototype_before_jquery')) {
  50. function wp_prototype_before_jquery( $js_array ) {
  51. if ( false === $jquery = array_search( 'jquery', $js_array ) )
  52. return $js_array;
  53. if ( false === $prototype = array_search( 'prototype', $js_array ) )
  54. return $js_array;
  55. if ( $prototype < $jquery )
  56. return $js_array;
  57. unset($js_array[$prototype]);
  58. array_splice( $js_array, $jquery, 0, 'prototype' );
  59. return $js_array;
  60. }
  61. add_filter( 'print_scripts_array', 'wp_prototype_before_jquery' );
  62. }
  63. define('CFZT_API_POST_UPDATE', 'http://app.zannel.com/api/update.json');
  64. define('CFZT_API_GET_UPDATES', 'http://app.zannel.com/api/user/###USERNAME###/updates.json');
  65. define('CFZT_API_COMMENT_URL', 'http://app.zannel.com/api/update/###ZUPDATEHASH###/comments.json');
  66. define('CFZT_PROFILE_URL', 'http://zannel.com/###USERNAME###');
  67. define('CFZT_TEST_LOGIN_URL', 'http://app.zannel.com/api/user/###USERNAME###.json');
  68. function cfzt_install() {
  69. global $wpdb;
  70. $cfzt_install = new zannel_tools;
  71. $wpdb->cfzt = $wpdb->prefix.'cfzt_zannel';
  72. $charset_collate = '';
  73. if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) {
  74. if (!empty($wpdb->charset)) {
  75. $charset_collate .= " DEFAULT CHARACTER SET $wpdb->charset";
  76. }
  77. if (!empty($wpdb->collate)) {
  78. $charset_collate .= " COLLATE $wpdb->collate";
  79. }
  80. }
  81. $result = $wpdb->query("
  82. CREATE TABLE `$wpdb->cfzt` (
  83. `id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  84. `zupdate_hash` VARCHAR( 255 ) NOT NULL ,
  85. `zupdate_type` VARCHAR( 255 ) NOT NULL ,
  86. `zupdate_tags` VARCHAR( 255 ) NOT NULL ,
  87. `zupdate_timestamp` VARCHAR( 255 ) NOT NULL ,
  88. `zupdate_description` VARCHAR( 255 ) NOT NULL ,
  89. `zupdate_user` VARCHAR( 255 ) NOT NULL ,
  90. `zupdate_media` VARCHAR( 500 ) ,
  91. `zupdate_embed_code` VARCHAR ( 500 ) ,
  92. `zupdate_url` VARCHAR( 255 ) NOT NULL ,
  93. `modified` DATETIME NOT NULL ,
  94. INDEX ( `zupdate_hash` )
  95. ) $charset_collate
  96. ");
  97. foreach ($cfzt_install->options as $option) {
  98. add_option('cfzt_'.$option, $cfzt_install->$option);
  99. }
  100. add_option('cfzt_zupdate_hash', '');
  101. }
  102. register_activation_hook(CFZT_FILE, 'cfzt_install');
  103. class zannel_tools {
  104. function zannel_tools() {
  105. $this->options = array(
  106. 'zannel_username'
  107. , 'zannel_password'
  108. , 'create_blog_posts'
  109. , 'default_post_title'
  110. , 'create_digest'
  111. , 'create_digest_weekly'
  112. , 'digest_daily_time'
  113. , 'digest_weekly_time'
  114. , 'digest_weekly_day'
  115. , 'digest_title'
  116. , 'digest_title_weekly'
  117. , 'blog_post_author'
  118. , 'blog_post_category'
  119. , 'blog_post_tags'
  120. , 'notify_zannel'
  121. , 'sidebar_zupdate_count'
  122. , 'zupdate_from_sidebar'
  123. , 'give_cfzt_credit'
  124. , 'exclude_reply_zupdates'
  125. , 'last_zupdate_download'
  126. , 'doing_zupdate_download'
  127. , 'doing_digest_post'
  128. , 'install_date'
  129. , 'js_lib'
  130. , 'digest_zupdate_order'
  131. , 'notify_zannel_default'
  132. );
  133. $this->zannel_username = '';
  134. $this->zannel_password = '';
  135. $this->create_blog_posts = '0';
  136. $this->default_post_title = 'New Update from Zannel!';
  137. $this->create_digest = '0';
  138. $this->create_digest_weekly = '0';
  139. $this->digest_daily_time = null;
  140. $this->digest_weekly_time = null;
  141. $this->digest_weekly_day = null;
  142. $this->digest_title = __("Zannel Updates for %s", 'zannel-tools');
  143. $this->digest_title_weekly = __("Zannel Weekly Updates for %s", 'zannel-tools');
  144. $this->blog_post_author = '1';
  145. $this->blog_post_category = '1';
  146. $this->blog_post_tags = '';
  147. $this->notify_zannel = '0';
  148. $this->notify_zannel_default = '0';
  149. $this->sidebar_zupdate_count = '3';
  150. $this->zupdate_from_sidebar = '1';
  151. $this->give_cfzt_credit = '1';
  152. $this->exclude_reply_zupdates = '0';
  153. $this->install_date = '';
  154. $this->js_lib = 'jquery';
  155. $this->digest_zupdate_order = 'ASC';
  156. // not included in options
  157. $this->update_hash = '';
  158. $this->zupdate_prefix = 'New blog post';
  159. $this->zupdate_format = $this->zupdate_prefix.': %s %s';
  160. $this->last_digest_post = '';
  161. $this->last_zupdate_download = '';
  162. $this->doing_zupdate_download = '0';
  163. $this->doing_digest_post = '0';
  164. $this->version = '1.0';
  165. }
  166. function get_settings() {
  167. foreach ($this->options as $option) {
  168. $this->$option = get_option('cfzt_'.$option);
  169. }
  170. }
  171. // puts post fields into object propps
  172. function populate_settings() {
  173. foreach ($this->options as $option) {
  174. if (isset($_POST['cfzt_'.$option])) {
  175. $this->$option = stripslashes($_POST['cfzt_'.$option]);
  176. }
  177. }
  178. }
  179. // puts object props into wp option storage
  180. function update_settings() {
  181. if (current_user_can('manage_options')) {
  182. $this->sidebar_zupdate_count = intval($this->sidebar_zupdate_count);
  183. if ($this->sidebar_zupdate_count == 0) {
  184. $this->sidebar_zupdate_count = '3';
  185. }
  186. foreach ($this->options as $option) {
  187. update_option('cfzt_'.$option, $this->$option);
  188. }
  189. if (empty($this->install_date)) {
  190. update_option('cfzt_install_date', current_time('mysql'));
  191. }
  192. $this->initiate_digests();
  193. }
  194. }
  195. // figure out when the next weekly and daily digests will be
  196. function initiate_digests() {
  197. $next = ($this->create_digest) ? $this->calculate_next_daily_digest() : null;
  198. $this->next_daily_digest = $next;
  199. update_option('cfzt_next_daily_digest', $next);
  200. $next = ($this->create_digest_weekly) ? $this->calculate_next_weekly_digest() : null;
  201. $this->next_weekly_digest = $next;
  202. update_option('cfzt_next_weekly_digest', $next);
  203. }
  204. function calculate_next_daily_digest() {
  205. $optionDate = strtotime($this->digest_daily_time);
  206. $hour_offset = date("G", $optionDate);
  207. $minute_offset = date("i", $optionDate);
  208. $next = mktime($hour_offset, $minute_offset, 0);
  209. // may have to move to next day
  210. $now = time();
  211. while ($next < $now) {
  212. $next += 60 * 60 * 24;
  213. }
  214. return $next;
  215. }
  216. function calculate_next_weekly_digest() {
  217. $optionDate = strtotime($this->digest_weekly_time);
  218. $hour_offset = date("G", $optionDate);
  219. $minute_offset = date("i", $optionDate);
  220. $current_day_of_month = date("j");
  221. $current_day_of_week = date("w");
  222. $current_month = date("n");
  223. // if this week's day is less than today, go for next week
  224. $nextDay = $current_day_of_month - $current_day_of_week + $this->digest_weekly_day;
  225. if ($this->digest_weekly_day <= $current_day_of_week) {
  226. $nextDay += 7;
  227. }
  228. $next = mktime($hour_offset, $minute_offset, 0, $current_month, $nextDay);
  229. return $next;
  230. }
  231. function ping_digests() {
  232. // still busy
  233. if (get_option('cfzt_doing_digest_post') == '1') {
  234. return;
  235. }
  236. // check all the digest schedules
  237. if ($this->create_digest == 1) {
  238. $this->ping_digest('cfzt_next_daily_digest', 'cfzt_last_digest_post', $this->digest_title, (60 * 60 * 24 * 1));
  239. }
  240. if ($this->create_digest_weekly == 1) {
  241. $this->ping_digest('cfzt_next_weekly_digest', 'cfzt_last_digest_post_weekly', $this->digest_title_weekly, (60 * 60 * 24 * 7));
  242. }
  243. return;
  244. }
  245. function ping_digest($nextDateField, $lastDateField, $title, $defaultDuration) {
  246. $next = get_option($nextDateField);
  247. if ($next) {
  248. $next = $this->validateDate($next);
  249. $rightNow = time();
  250. if ($rightNow >= $next) {
  251. $start = get_option($lastDateField);
  252. $start = $this->validateDate($start, ($rightNow - $defaultDuration));
  253. if ($this->do_digest_post($start, $next, $title)) {
  254. update_option($lastDateField, $rightNow);
  255. update_option($nextDateField, ($next + $defaultDuration));
  256. } else {
  257. update_option($lastDateField, null);
  258. }
  259. }
  260. }
  261. }
  262. function validateDate($in, $default = 0) {
  263. if (!is_numeric($in)) {
  264. // try to convert what they gave us into a date
  265. $out = strtotime($in);
  266. // if that doesn't work, return the default
  267. if (!is_numeric($out)) {
  268. return $default;
  269. }
  270. return $out;
  271. }
  272. return $in;
  273. }
  274. function do_digest_post($start, $end, $title) {
  275. if (!$start || !$end) return false;
  276. // flag us as busy
  277. update_option('cfzt_doing_digest_post', '1');
  278. remove_action('publish_post', 'cfzt_notify_zannel', 99);
  279. remove_action('publish_post', 'cfzt_store_post_options', 1, 2);
  280. remove_action('save_post', 'cfzt_store_post_options', 1, 2);
  281. // see if there's any updates in the time range
  282. global $wpdb;
  283. $startGMT = gmdate("Y-m-d H:i:s", $start);
  284. $endGMT = gmdate("Y-m-d H:i:s", $end);
  285. // build sql
  286. $conditions = array();
  287. $conditions[] = "zupdate_timestamp >= '{$startGMT}'";
  288. $conditions[] = "zupdate_timestamp <= '{$endGMT}'";
  289. $conditions[] = "zupdate_description NOT LIKE '$this->zupdate_prefix%'";
  290. if ($this->exclude_reply_zupdates) {
  291. $conditions[] = "zupdate_description NOT LIKE '@%'";
  292. }
  293. $where = implode(' AND ', $conditions);
  294. $sql = "
  295. SELECT * FROM {$wpdb->cfzt}
  296. WHERE {$where}
  297. GROUP BY id
  298. ORDER BY zupdate_timestamp {$this->digest_zupdate_order}
  299. ";
  300. $zupdates = $wpdb->get_results($sql);
  301. if (count($zupdates) > 0) {
  302. $zupdates_to_post = array();
  303. foreach ($zupdates as $data) {
  304. $zupdate = new cfzt_zupdate;
  305. $zupdate->description = $data->description;
  306. $zupdate->cfzt_reply_zupdate = $data->cfzt_reply_zupdate;
  307. if (!$zupdate->zupdate_is_post_notification() || ($zupdate->zupdate_is_reply() && $this->exclude_reply_zupdates)) {
  308. $zupdates_to_post[] = $data;
  309. }
  310. }
  311. if (count($zupdates_to_post) > 0) {
  312. $content = '<ul class="cfzt_zupdate_digest">'."\n";
  313. foreach ($zupdates_to_post as $zupdate) {
  314. $content .= ' <li>'.cfzt_zupdate_display($zupdate, 'absolute').'</li>'."\n";
  315. }
  316. $content .= '</ul>'."\n";
  317. if ($this->give_cfzt_credit == '1') {
  318. $content .= '<p class="cfzt_credit">Powered by <a href="http://zannel.com">Zannel Tools</a>.</p>';
  319. }
  320. $post_data = array(
  321. 'post_content' => $wpdb->escape($content),
  322. 'post_title' => $wpdb->escape(sprintf($title, date('Y-m-d'))),
  323. 'post_date' => date('Y-m-d H:i:s', $end),
  324. 'post_category' => array($this->blog_post_category),
  325. 'post_status' => 'publish',
  326. 'post_author' => $wpdb->escape($this->blog_post_author)
  327. );
  328. $post_id = wp_insert_post($post_data);
  329. add_post_meta($post_id, 'cfzt_zupdated', '1', true);
  330. wp_set_post_tags($post_id, $this->blog_post_tags);
  331. }
  332. }
  333. add_action('publish_post', 'cfzt_notify_zannel', 99);
  334. add_action('publish_post', 'cfzt_store_post_options', 1, 2);
  335. add_action('save_post', 'cfzt_store_post_options', 1, 2);
  336. update_option('cfzt_doing_digest_post', '0');
  337. return true;
  338. }
  339. function zupdate_download_interval() {
  340. return 1800;
  341. }
  342. function do_zupdate($zupdate = '') {
  343. if (empty($this->zannel_username)
  344. || empty($this->zannel_password)
  345. || empty($zupdate)
  346. || empty($zupdate->zupdate_description)
  347. ) {
  348. return;
  349. }
  350. require_once(ABSPATH.WPINC.'/class-snoopy.php');
  351. $snoop = new Snoopy;
  352. $snoop->agent = 'Zannel Tools http://zannel.com';
  353. $snoop->rawheaders = array(
  354. 'X-Zannel-Client' => 'Zannel Tools'
  355. , 'X-Zannel-Client-Version' => $this->version
  356. , 'X-Zannel-Client-URL' => 'http://zannel.com'
  357. );
  358. $snoop->set_submit_multipart();
  359. $data_arguments = array(
  360. 'authuser' => $this->zannel_username,
  361. 'authpass' => $this->zannel_password,
  362. 'description' => $zupdate->zupdate_description
  363. );
  364. if ($zupdate->media) {
  365. $snoop->submit(
  366. CFZT_API_POST_UPDATE
  367. , $data_arguments
  368. , $zupdate->media
  369. );
  370. }
  371. else {
  372. $snoop->submit(
  373. CFZT_API_POST_UPDATE
  374. , $data_arguments
  375. );
  376. }
  377. if (strpos($snoop->response_code, '200')) {
  378. update_option('cfzt_last_zupdate_download', strtotime('-28 minutes'));
  379. return true;
  380. }
  381. return false;
  382. }
  383. function do_blog_post_zupdate($post_id = 0) {
  384. if ($this->notify_zannel == '0'
  385. || $post_id == 0
  386. || get_post_meta($post_id, 'cfzt_zupdated', true) == '1'
  387. || get_post_meta($post_id, 'cfzt_notify_zannel', true) == 'no'
  388. ) {
  389. return;
  390. }
  391. $post = get_post($post_id);
  392. // check for an edited post before TT was installed
  393. if ($post->post_date <= $this->install_date) {
  394. return;
  395. }
  396. // check for private posts
  397. if ($post->post_status != 'publish') {
  398. return;
  399. }
  400. $zupdate = new cfzt_zupdate;
  401. $url = apply_filters('zupdate_blog_post_url', get_permalink($post_id));
  402. $zupdate->zupdate_description = sprintf(__($this->zupdate_format, 'zannel-tools'), $post->post_title, $url);
  403. $zupdate->media = $this->get_post_media($post_id);
  404. $this->do_zupdate($zupdate);
  405. add_post_meta($post_id, 'cfzt_zupdated', '1', true);
  406. }
  407. function get_post_media($post_id) {
  408. global $wpdb;
  409. $sql = '
  410. SELECT ID
  411. FROM '.$wpdb->posts.'
  412. WHERE post_type="attachment"
  413. AND post_parent='.$post_id.'
  414. ';
  415. $attachment_ids = $wpdb->get_results($sql);
  416. if (!$attachment_ids) {
  417. return false;
  418. }
  419. $path_to_uploads = wp_upload_dir();
  420. $path_to_media = trailingslashit($path_to_uploads['basedir']);
  421. $biggest_file = '';
  422. $biggest_file_size = '';
  423. foreach ($attachment_ids as $attachment) {
  424. $media = get_post_meta($attachment->ID,'_wp_attached_file',true);
  425. if (!empty($media)) {
  426. if (version_compare(get_bloginfo('version'),'2.6.5','>')) {
  427. // 2.7 gives us a relative path, while 2.6.5 and 2.5.1 give us a full path
  428. $media = $path_to_media.$media;
  429. }
  430. $file_size = filesize($media);
  431. if ($file_size >= $biggest_file_size) {
  432. $biggest_file = $media;
  433. $biggest_file_size = $file_size;
  434. }
  435. }
  436. }
  437. return $biggest_file;
  438. }
  439. function do_zupdate_post($zupdate) {
  440. global $wpdb;
  441. remove_action('publish_post', 'cfzt_notify_zannel', 99);
  442. remove_action('publish_post', 'cfzt_store_post_options', 1, 2);
  443. remove_action('save_post', 'cfzt_store_post_options', 1, 2);
  444. // if post type is video, then grab embed code
  445. if ($zupdate->type == "VIDEO") {
  446. $post_content = $zupdate->description.'<p>'.$zupdate->embed_code.'</p>';
  447. }
  448. else if ($zupdate->type == "IMAGE") {
  449. $media = unserialize($zupdate->media);
  450. $post_content = $zupdate->description.'<p><img src="'.$media->large.'" /></p>';
  451. }
  452. else {
  453. $post_content = $zupdate->description;
  454. }
  455. if (empty($zupdate->description)) {
  456. // we need a post title, so if it's empty, use the default one.
  457. $post_title = get_option('cfzt_default_post_title');
  458. }
  459. if ($this->exclude_reply_zupdates && ereg('^@',$zupdate->description)) {
  460. // don't create post if is reply and exclude replies is set
  461. return;
  462. }
  463. else {
  464. $post_title = $zupdate->description;
  465. }
  466. $data = array(
  467. 'post_content' => $wpdb->escape(cfzt_make_clickable($post_content))
  468. , 'post_title' => $wpdb->escape(trim_add_elipsis($post_title, 30))
  469. , 'post_date' => get_date_from_gmt(gmdate('Y-m-d H:i:s', strtotime($zupdate->timestamp)))
  470. , 'post_category' => array($this->blog_post_category)
  471. , 'post_status' => 'publish'
  472. , 'post_author' => $wpdb->escape($this->blog_post_author)
  473. );
  474. $post_id = wp_insert_post($data);
  475. update_post_meta($post_id, 'cfzt_notify_zannel', 'no', true);
  476. add_post_meta($post_id, 'cfzt_zupdate_id', $zupdate->hashcode, true);
  477. wp_set_post_tags($post_id, $this->blog_post_tags);
  478. add_action('publish_post', 'cfzt_notify_zannel', 99);
  479. add_action('publish_post', 'cfzt_store_post_options', 1, 2);
  480. add_action('save_post', 'cfzt_store_post_options', 1, 2);
  481. }
  482. }
  483. class cfzt_zupdate {
  484. function cfzt_zupdate(
  485. $hashcode = '',
  486. $type = '',
  487. $tags = '',
  488. $timestamp = '',
  489. $description = '',
  490. $user = '',
  491. $media = '',
  492. $embed_code = '',
  493. $url = ''
  494. ){
  495. $this->id = '';
  496. $this->hashcode = $hashcode;
  497. $this->type = $type;
  498. $this->tags = $tags;
  499. $this->timestamp = $timestamp;
  500. $this->description = $description;
  501. $this->user = $user;
  502. $this->media = $media;
  503. $this->embed_code = $embed_code;
  504. $this->url = $url;
  505. $this->modified = '';
  506. }
  507. function cfztdate_to_time($date) {
  508. $parts = explode(' ', $date);
  509. $date = strtotime($parts[1].' '.$parts[2].', '.$parts[5].' '.$parts[3]);
  510. return $date;
  511. }
  512. function zupdate_post_exists() {
  513. global $wpdb;
  514. $test = $wpdb->get_results("
  515. SELECT *
  516. FROM $wpdb->postmeta
  517. WHERE meta_key = 'cfzt_zupdate_id'
  518. AND meta_value = '".$wpdb->escape($this->hashcode)."'
  519. ");
  520. if (count($test) > 0) {
  521. return true;
  522. }
  523. return false;
  524. }
  525. function zupdate_is_post_notification() {
  526. global $cfzt;
  527. if (substr($this->description, 0, strlen($cfzt->zupdate_prefix)) == $cfzt->zupdate_prefix) {
  528. return true;
  529. }
  530. return false;
  531. }
  532. function zupdate_is_reply() {
  533. return !empty($this->cfzt_reply_zupdate);
  534. }
  535. function add() {
  536. global $wpdb, $cfzt;
  537. $wpdb->query("
  538. INSERT
  539. INTO $wpdb->cfzt
  540. ( id
  541. , zupdate_hash
  542. , zupdate_type
  543. , zupdate_tags
  544. , zupdate_timestamp
  545. , zupdate_description
  546. , zupdate_user
  547. , zupdate_media
  548. , zupdate_embed_code
  549. , zupdate_url
  550. , modified
  551. )
  552. VALUES
  553. ( '".$wpdb->escape($this->id)."'
  554. , '".$wpdb->escape($this->hashcode)."'
  555. , '".$wpdb->escape($this->type)."'
  556. , '".$wpdb->escape($this->tags)."'
  557. , '".date('Y-m-d H:i:s', strtotime($this->timestamp))."'
  558. , '".$wpdb->escape($this->description)."'
  559. , '".$wpdb->escape($this->user)."'
  560. , '".$wpdb->escape($this->media)."'
  561. , '".$wpdb->escape($this->embed_code)."'
  562. , '".$wpdb->escape($this->url)."'
  563. , NOW()
  564. )
  565. ");
  566. do_action('cfzt_add_zupdate', $this);
  567. if ($cfzt->create_blog_posts == '1' && !$this->zupdate_post_exists() && !$this->zupdate_is_post_notification()) {
  568. $cfzt->do_zupdate_post($this);
  569. }
  570. }
  571. }
  572. function cfzt_api_status_show_url($id) {
  573. return str_replace('###ID###', $id, CFZT_API_STATUS_SHOW);
  574. }
  575. function cfzt_profile_url($username) {
  576. return str_replace('###USERNAME###', $username, CFZT_PROFILE_URL);
  577. }
  578. function cfzt_profile_link($username, $prefix = '', $suffix = '') {
  579. return $prefix.'<a href="'.cfzt_profile_url($username).'">'.$username.'</a>'.$suffix;
  580. }
  581. function cfzt_hashtag_url($hashtag) {
  582. $hashtag = urlencode('#'.$hashtag);
  583. return str_replace('###HASHTAG###', $hashtag, CFZT_HASHTAG_URL);
  584. }
  585. function cfzt_hashtag_link($hashtag, $prefix = '', $suffix = '') {
  586. return $prefix.'<a href="'.cfzt_hashtag_url($hashtag).'">'.htmlspecialchars($hashtag).'</a>'.$suffix;
  587. }
  588. function cfzt_status_url($username, $status) {
  589. return str_replace(
  590. array(
  591. '###USERNAME###'
  592. , '###STATUS###'
  593. )
  594. , array(
  595. $username
  596. , $status
  597. )
  598. , CFZT_STATUS_URL
  599. );
  600. }
  601. function cfzt_login_test($username, $password) {
  602. require_once(ABSPATH.WPINC.'/class-snoopy.php');
  603. $snoop = new Snoopy;
  604. $snoop->agent = 'Zannel Tools http://zannel.com';
  605. $snoop->user = $username;
  606. $snoop->pass = $password;
  607. $arguments = array(
  608. 'zannel_login_test' => 'test'
  609. );
  610. $snoop->submit(str_replace('###USERNAME###',$username,CFZT_TEST_LOGIN_URL),$arguments);
  611. if (strpos($snoop->response_code, '200')) {
  612. return __("Login succeeded, you're good to go.", 'zannel-tools');
  613. } else {
  614. return print(__('Sorry, login failed. Please check your username and password', 'zannel-tools'));
  615. }
  616. }
  617. function cfzt_ping_digests() {
  618. global $cfzt;
  619. $cfzt->ping_digests();
  620. }
  621. function cfzt_update_zupdates() {
  622. // let the last update run for 10 minutes
  623. if (time() - intval(get_option('cfzt_doing_zupdate_download')) < 600) {
  624. return;
  625. }
  626. // wait 10 min between downloads
  627. if (time() - intval(get_option('cfzt_last_zupdate_download')) < 600) {
  628. return;
  629. }
  630. update_option('cfzt_doing_zupdate_download', time());
  631. global $wpdb, $cfzt;
  632. if (empty($cfzt->zannel_username) || empty($cfzt->zannel_password)) {
  633. update_option('cfzt_doing_zupdate_download', '0');
  634. return;
  635. }
  636. require_once(ABSPATH.WPINC.'/class-snoopy.php');
  637. $snoop = new Snoopy;
  638. $snoop->agent = 'Zannel Tools http://zannel.com';
  639. $snoop->user = $cfzt->zannel_username;
  640. $snoop->pass = $cfzt->zannel_password;
  641. $url = str_replace('###USERNAME###',$cfzt->zannel_username,CFZT_API_GET_UPDATES);
  642. $snoop->fetch($url);
  643. if (!strpos($snoop->response_code, '200')) {
  644. update_option('cfzt_doing_zupdate_download', '0');
  645. return;
  646. }
  647. $data = $snoop->results;
  648. // hash results to see if they're any different than the last update, if so, return
  649. $hash = md5($data);
  650. if ($hash == get_option('cfzt_zupdate_hash')) {
  651. update_option('cfzt_last_zupdate_download', time());
  652. update_option('cfzt_doing_zupdate_download', '0');
  653. return;
  654. }
  655. $json = new Services_JSON();
  656. $zupdates = $json->decode($data);
  657. $zupdates = $zupdates->updates;
  658. if (is_array($zupdates) && count($zupdates) > 0) {
  659. $zupdate_ids = array();
  660. foreach ($zupdates as $zupdate) {
  661. $zupdate_ids[] = $wpdb->escape($zupdate->hashcode);
  662. }
  663. $existing_ids = $wpdb->get_col("
  664. SELECT zupdate_hash
  665. FROM $wpdb->cfzt
  666. WHERE zupdate_hash
  667. IN ('".implode("', '", $zupdate_ids)."')
  668. ");
  669. $new_zupdates = array();
  670. foreach ($zupdates as $zupdate_data) {
  671. if (!empty($zupdate_data->media)) {
  672. $zupdate_data->media = serialize($zupdate_data->media);
  673. }
  674. else {
  675. $zupdate_data->media = "";
  676. }
  677. if (!$existing_ids || !in_array($zupdate_data->hashcode, $existing_ids)) {
  678. $zupdate = new cfzt_zupdate(
  679. $zupdate_data->hashcode
  680. , $zupdate_data->type
  681. , $zupdate_data->tags
  682. , $zupdate_data->timestamp
  683. , $zupdate_data->description
  684. , $zupdate_data->user->name
  685. , $zupdate_data->media
  686. , $zupdate_data->embedCode
  687. , $zupdate_data->zannelurl
  688. );
  689. // make sure we haven't downloaded someone else's updates - happens sometimes due to Zannel hiccups
  690. if (strtolower($zupdate_data->user->name) == strtolower($cfzt->zannel_username)) {
  691. $new_zupdates[] = $zupdate;
  692. }
  693. }
  694. }
  695. foreach ($new_zupdates as $zupdate) {
  696. $zupdate->add();
  697. }
  698. }
  699. cfzt_reset_zupdate_checking($hash, time());
  700. }
  701. function cfzt_reset_zupdate_checking($hash = '', $time = 0) {
  702. if (!current_user_can('manage_options')) {
  703. return;
  704. }
  705. update_option('cfzt_zupdate_hash', $hash);
  706. update_option('cfzt_last_zupdate_download', $time);
  707. update_option('cfzt_doing_zupdate_download', '0');
  708. }
  709. function cfzt_notify_zannel($post_id) {
  710. global $cfzt;
  711. $cfzt->do_blog_post_zupdate($post_id);
  712. }
  713. add_action('publish_post', 'cfzt_notify_zannel', 99);
  714. function cfzt_sidebar_zupdates() {
  715. global $wpdb, $cfzt;
  716. if ($cfzt->exclude_reply_zupdates) {
  717. $where = "AND zupdate_description NOT LIKE '@%' ";
  718. }
  719. else {
  720. $where = '';
  721. }
  722. $zupdates = $wpdb->get_results("
  723. SELECT *
  724. FROM $wpdb->cfzt
  725. WHERE zupdate_description NOT LIKE '$cfzt->zupdate_prefix%'
  726. $where
  727. GROUP BY id
  728. ORDER BY zupdate_timestamp DESC
  729. LIMIT $cfzt->sidebar_zupdate_count
  730. ");
  731. $output = '<div class="cfzt_zupdates">'."\n"
  732. .' <ul>'."\n";
  733. if (count($zupdates) > 0) {
  734. foreach ($zupdates as $zupdate) {
  735. $output .= ' <li>'.cfzt_zupdate_display($zupdate).'</li>'."\n";
  736. }
  737. }
  738. else {
  739. $output .= ' <li>'.__('No Updates available at the moment.', 'zannel-tools').'</li>'."\n";
  740. }
  741. if (!empty($cfzt->zannel_username)) {
  742. $output .= ' <li class="cfzt_more_updates"><a href="'.cfzt_profile_url($cfzt->zannel_username).'">More Updates...</a></li>'."\n";
  743. }
  744. $output .= '</ul>';
  745. if ($cfzt->zupdate_from_sidebar == '1' && !empty($cfzt->zannel_username) && !empty($cfzt->zannel_password)) {
  746. $output .= cfzt_zupdate_form('input', 'onsubmit="cfztPostZupdate(); return false;"');
  747. $output .= ' <p id="cfzt_zupdate_posted_msg">'.__('Posting Update...', 'zannel-tools').'</p>';
  748. }
  749. if ($cfzt->give_cfzt_credit == '1') {
  750. $output .= '<p class="cfzt_credit">Powered by <a href="http://zannel.com">Zannel Tools</a>.</p>';
  751. }
  752. $output .= '</div>';
  753. print($output);
  754. }
  755. function cfzt_latest_zupdate() {
  756. global $wpdb, $cfzt;
  757. $zupdates = $wpdb->get_results("
  758. SELECT *
  759. FROM $wpdb->cfzt
  760. WHERE zupdate_description NOT LIKE '$cfzt->zupdate_prefix%'
  761. GROUP BY id
  762. ORDER BY zupdate_timestamp DESC
  763. LIMIT 1
  764. ");
  765. if (count($zupdates) == 1) {
  766. foreach ($zupdates as $zupdate) {
  767. $output = cfzt_zupdate_display($zupdate);
  768. }
  769. }
  770. else {
  771. $output = __('No Updates available at the moment.', 'zannel-tools');
  772. }
  773. print($output);
  774. }
  775. function cfzt_zupdate_display($zupdate, $time = 'relative') {
  776. global $cfzt;
  777. $text = cfzt_make_clickable(wp_specialchars($zupdate->zupdate_description)).' ';
  778. switch ($time) {
  779. case 'relative':
  780. $time_display = cfzt_relativeTime($zupdate->zupdate_timestamp, 3);
  781. break;
  782. case 'absolute':
  783. $time_display = '#';
  784. break;
  785. }
  786. switch (strtolower($zupdate->zupdate_type)) {
  787. case 'text':
  788. $output = $text.' <a href="'.$zupdate->zupdate_url.'">'.$time_display.'</a>';
  789. break;
  790. case 'image':
  791. $media = unserialize($zupdate->zupdate_media);
  792. $output = '<a href="'.$zupdate->zupdate_url.'"><span class="zannel_thumb"><img src="'.$media->medium.'"/></span></a> '.$text.'<a href="'.$zupdate->zupdate_url.'">'.$time_display.'</a>';
  793. break;
  794. case 'video':
  795. $media = unserialize($zupdate->zupdate_media);
  796. $output = '<a href="'.$zupdate->zupdate_url.'"><span class="zannel_thumb"><img src="'.$media->medium.'"/></span></a> '.$text.'<a href="'.$zupdate->zupdate_url.'">'.$time_display.'</a>';
  797. break;
  798. }
  799. return $output;
  800. }
  801. function cfzt_make_clickable($zupdate) {
  802. $zupdate .= ' ';
  803. $zupdate = preg_replace_callback(
  804. '/@([a-zA-Z0-9_]{1,15})([) ])/'
  805. , create_function(
  806. '$matches'
  807. , 'return cfzt_profile_link($matches[1], \'@\', $matches[2]);'
  808. )
  809. , $zupdate
  810. );
  811. $zupdate = preg_replace_callback(
  812. '/\#([a-zA-Z0-9_]{1,15}) /'
  813. , create_function(
  814. '$matches'
  815. , 'return cfzt_hashtag_link($matches[1], \'#\', \' \');'
  816. )
  817. , $zupdate
  818. );
  819. if (function_exists('make_chunky')) {
  820. return make_chunky($zupdate);
  821. }
  822. else {
  823. return make_clickable($zupdate);
  824. }
  825. }
  826. function cfzt_zupdate_form($type = 'input', $extra = '') {
  827. $output = '';
  828. if (current_user_can('publish_posts')) {
  829. $output .= '
  830. <form action="'.get_bloginfo('wpurl').'/index.php" method="post" id="cfzt_zupdate_form" '.$extra.'>
  831. <fieldset>
  832. ';
  833. switch ($type) {
  834. case 'input':
  835. $output .= '
  836. <p><input type="text" size="20" maxlength="255" id="cfzt_zupdate_text" name="cfzt_zupdate_text" onkeyup="cfztCharCount();" /></p>
  837. <input type="hidden" name="cfzt_action" value="cfzt_post_zupdate_sidebar" />
  838. <script type="text/javascript">
  839. //<![CDATA[
  840. function cfztCharCount() {
  841. var count = document.getElementById("cfzt_zupdate_text").value.length;
  842. if (count > 0) {
  843. document.getElementById("cfzt_char_count").innerHTML = 255 - count;
  844. }
  845. else {
  846. document.getElementById("cfzt_char_count").innerHTML = "";
  847. }
  848. }
  849. setTimeout("cfztCharCount();", 500);
  850. document.getElementById("cfzt_zupdate_form").setAttribute("autocomplete", "off");
  851. //]]>
  852. </script>
  853. ';
  854. break;
  855. case 'textarea':
  856. $output .= '
  857. <p><textarea type="text" cols="60" rows="5" maxlength="255" id="cfzt_zupdate_text" name="cfzt_zupdate_text" onkeyup="cfztCharCount();"></textarea></p>
  858. <input type="hidden" name="cfzt_action" value="cfzt_post_zupdate_admin" />
  859. <script type="text/javascript">
  860. //<![CDATA[
  861. function cfztCharCount() {
  862. var count = document.getElementById("cfzt_zupdate_text").value.length;
  863. if (count > 0) {
  864. document.getElementById("cfzt_char_count").innerHTML = (255 - count) + "'.__(' characters remaining', 'zannel-tools').'";
  865. }
  866. else {
  867. document.getElementById("cfzt_char_count").innerHTML = "";
  868. }
  869. }
  870. setTimeout("cfztCharCount();", 500);
  871. document.getElementById("cfzt_zupdate_form").setAttribute("autocomplete", "off");
  872. //]]>
  873. </script>
  874. ';
  875. break;
  876. }
  877. $output .= '
  878. <p>
  879. <input type="submit" id="cfzt_zupdate_submit" name="cfzt_zupdate_submit" value="'.__('Post Update!', 'zannel-tools').'" />
  880. <span id="cfzt_char_count"></span>
  881. </p>
  882. <div class="clear"></div>
  883. </fieldset>
  884. </form>
  885. ';
  886. }
  887. return $output;
  888. }
  889. function cfzt_widget_init() {
  890. if (!function_exists('register_sidebar_widget')) {
  891. return;
  892. }
  893. function cfzt_widget($args) {
  894. extract($args);
  895. $options = get_option('cfzt_widget');
  896. $title = $options['title'];
  897. if (empty($title)) {
  898. }
  899. echo $before_widget . $before_title . $title . $after_title;
  900. cfzt_sidebar_zupdates();
  901. echo $after_widget;
  902. }
  903. register_sidebar_widget(array(__('Zannel Tools', 'zannel-tools'), 'widgets'), 'cfzt_widget');
  904. function cfzt_widget_control() {
  905. $options = get_option('cfzt_widget');
  906. if (!is_array($options)) {
  907. $options = array(
  908. 'title' => __("What I'm Doing...", 'zannel-tools')
  909. );
  910. }
  911. if (isset($_POST['cfzt_action']) && $_POST['cfzt_action'] == 'cfzt_update_widget_options') {
  912. $options['title'] = strip_tags(stripslashes($_POST['cfzt_widget_title']));
  913. update_option('cfzt_widget', $options);
  914. // reset checking so that sidebar isn't blank if this is the first time activating
  915. cfzt_reset_zupdate_checking();
  916. cfzt_update_zupdates();
  917. }
  918. // Be sure you format your options to be valid HTML attributes.
  919. $title = htmlspecialchars($options['title'], ENT_QUOTES);
  920. // Here is our little form segment. Notice that we don't need a
  921. // complete form. This will be embedded into the existing form.
  922. print('
  923. <p style="text-align:right;"><label for="cfzt_widget_title">' . __('Title:') . ' <input style="width: 200px;" id="cfzt_widget_title" name="cfzt_widget_title" type="text" value="'.$title.'" /></label></p>
  924. <p>'.__('Find additional Zannel Tools options on the <a href="options-general.php?page=zannel-tools.php">Zannel Tools Options page</a>.', 'zannel-tools').'
  925. <input type="hidden" id="cfzt_action" name="cfzt_action" value="cfzt_update_widget_options" />
  926. ');
  927. }
  928. register_widget_control(array(__('Zannel Tools', 'zannel-tools'), 'widgets'), 'cfzt_widget_control', 300, 100);
  929. }
  930. add_action('widgets_init', 'cfzt_widget_init');
  931. function cfzt_init() {
  932. global $wpdb, $cfzt;
  933. $cfzt = new zannel_tools;
  934. $wpdb->cfzt = $wpdb->prefix.'cfzt_zannel';
  935. $cfzt->get_settings();
  936. if (($cfzt->last_zupdate_download + $cfzt->zupdate_download_interval()) < time()) {
  937. add_action('shutdown', 'cfzt_update_zupdates');
  938. add_action('shutdown', 'cfzt_ping_digests');
  939. }
  940. if (is_admin() || $cfzt->zupdate_from_sidebar) {
  941. switch ($cfzt->js_lib) {
  942. case 'jquery':
  943. wp_enqueue_script('jquery');
  944. break;
  945. case 'prototype':
  946. wp_enqueue_script('prototype');
  947. break;
  948. }
  949. }
  950. }
  951. add_action('init', 'cfzt_init');
  952. function cfzt_head() {
  953. global $cfzt;
  954. if ($cfzt->zupdate_from_sidebar) {
  955. print('
  956. <link rel="stylesheet" type="text/css" href="'.get_bloginfo('wpurl').'/index.php?cfzt_action=cfzt_css" />
  957. <script type="text/javascript" src="'.get_bloginfo('wpurl').'/index.php?cfzt_action=cfzt_js"></script>
  958. ');
  959. }
  960. }
  961. add_action('wp_head', 'cfzt_head');
  962. function cfzt_head_admin() {
  963. print('
  964. <link rel="stylesheet" type="text/css" href="'.get_bloginfo('wpurl').'/index.php?cfzt_action=cfzt_css_admin" />
  965. <script type="text/javascript" src="'.get_bloginfo('wpurl').'/index.php?cfzt_action=cfzt_js_admin"></script>
  966. ');
  967. }
  968. add_action('admin_head', 'cfzt_head_admin');
  969. function cfzt_request_handler() {
  970. global $wpdb, $cfzt;
  971. if (!empty($_GET['cfzt_action'])) {
  972. switch($_GET['cfzt_action']) {
  973. case 'cfzt_update_zupdates':
  974. cfzt_update_zupdates();
  975. wp_redirect(get_bloginfo('wpurl').'/wp-admin/options-general.php?page=zannel-tools.php&zupdates-updated=true');
  976. die();
  977. break;
  978. case 'cfzt_reset_zupdate_checking':
  979. cfzt_reset_zupdate_checking();
  980. wp_redirect(get_bloginfo('wpurl').'/wp-admin/options-general.php?page=zannel-tools.php&zupdate-checking-reset=true');
  981. die();
  982. break;
  983. case 'cfzt_js':
  984. remove_action('shutdown', 'cfzt_ping_digests');
  985. header("Content-type: text/javascript");
  986. switch ($cfzt->js_lib) {
  987. case 'jquery':
  988. ?>
  989. function cfztPostZupdate() {
  990. var zupdate_field = jQuery('#cfzt_zupdate_text');
  991. var zupdate_text = zupdate_field.val();
  992. if (zupdate_text == '') {
  993. return;
  994. }
  995. var zupdate_msg = jQuery("#cfzt_zupdate_posted_msg");
  996. jQuery.post(
  997. "<?php bloginfo('wpurl'); ?>/index.php"
  998. , {
  999. cfzt_action: "cfzt_post_zupdate_sidebar"
  1000. , cfzt_zupdate_text: zupdate_text
  1001. }
  1002. , function(data) {
  1003. zupdate_msg.html(data);
  1004. cfztSetReset();
  1005. }
  1006. );
  1007. zupdate_field.val('').focus();
  1008. jQuery('#cfzt_char_count').html('');
  1009. jQuery("#cfzt_zupdate_posted_msg").show();
  1010. }
  1011. function cfztSetReset() {
  1012. setTimeout('cfztReset();', 2000);
  1013. }
  1014. function cfztReset() {
  1015. jQuery('#cfzt_zupdate_posted_msg').hide();
  1016. }
  1017. <?php
  1018. break;
  1019. case 'prototype':
  1020. ?>
  1021. function cfztPostZupdate() {
  1022. var zupdate_field = $('cfzt_zupdate_text');
  1023. var zupdate_text = zupdate_field.value;
  1024. if (zupdate_text == '') {
  1025. return;
  1026. }
  1027. var zupdate_msg = $("cfzt_zupdate_posted_msg");
  1028. var cfztAjax = new Ajax.Updater(
  1029. zupdate_msg,
  1030. "<?php bloginfo('wpurl'); ?>/index.php",
  1031. {
  1032. method: "post",
  1033. parameters: "cfzt_action=cfzt_post_zupdate_sidebar&cfzt_zupdate_text=" + zupdate_text,
  1034. onComplete: cfztSetReset
  1035. }
  1036. );
  1037. zupdate_field.value = '';
  1038. zupdate_field.focus();
  1039. $('cfzt_char_count').innerHTML = '';
  1040. zupdate_msg.style.display = 'block';
  1041. }
  1042. function cfztSetReset() {
  1043. setTimeout('cfztReset();', 2000);
  1044. }
  1045. function cfztReset() {
  1046. $('cfzt_zupdate_posted_msg').style.display = 'none';
  1047. }
  1048. <?php
  1049. break;
  1050. }
  1051. die();
  1052. break;
  1053. case 'cfzt_css':
  1054. remove_action('shutdown', 'cfzt_ping_digests');
  1055. header("Content-Type: text/css");
  1056. ?>
  1057. #cfzt_zupdate_form {
  1058. margin: 0;
  1059. padding: 5px 0;
  1060. }
  1061. #cfzt_zupdate_form fieldset {
  1062. border: 0;
  1063. }
  1064. #cfzt_zupdate_form fieldset #cfzt_zupdate_submit {
  1065. float: right;
  1066. margin-right: 10px;
  1067. }
  1068. #cfzt_zupdate_form fieldset #cfzt_char_count {
  1069. color: #666;
  1070. }
  1071. #cfzt_zupdate_posted_msg {
  1072. background: #ffc;
  1073. display: none;
  1074. margin: 0 0 5px 0;
  1075. padding: 5px;
  1076. }
  1077. #cfzt_zupdate_form div.clear {
  1078. clear: both;
  1079. float: none;
  1080. }
  1081. <?php
  1082. die();
  1083. break;
  1084. case 'cfzt_js_admin':
  1085. remove_action('shutdown', 'cfzt_ping_digests');
  1086. header("Content-Type: text/javascript");
  1087. switch ($cfzt->js_lib) {
  1088. case 'jquery':
  1089. ?>
  1090. function cfztTestLogin() {
  1091. var result = jQuery('#cfzt_login_test_result');
  1092. result.show().addClass('cfzt_login_result_wait').html('<?php _e('Testing...', 'zannel-tools'); ?>');
  1093. jQuery.post(
  1094. "<?php bloginfo('wpurl'); ?>/index.php"
  1095. , {
  1096. cfzt_action: "cfzt_login_test"
  1097. , cfzt_zannel_username: jQuery('#cfzt_zannel_username').val()
  1098. , cfzt_zannel_password: jQuery('#cfzt_zannel_password').val()
  1099. }
  1100. , function(data) {
  1101. result.html(data).removeClass('cfzt_login_result_wait');
  1102. setTimeout('cfztTestLoginResult();', 5000);
  1103. }
  1104. );
  1105. };
  1106. function cfztTestLoginResult() {
  1107. jQuery('#cfzt_login_test_result').fadeOut('slow');
  1108. };
  1109. (function($){
  1110. jQuery.fn.timepicker = function(){
  1111. var hrs = new Array();
  1112. for(var h = 1; h <= 12; hrs.push(h++));
  1113. var mins = new Array();
  1114. for(var m = 0; m < 60; mins.push(m++));
  1115. var ap = new Array('am', 'pm');
  1116. function pad(n) {
  1117. n = n.toString();
  1118. return n.length == 1 ? '0' + n : n;
  1119. }
  1120. this.each(function() {
  1121. var v = $(this).val();
  1122. if (!v) v = new Date();
  1123. var d = new Date(v);
  1124. var h = d.getHours();
  1125. var m = d.getMinutes();
  1126. var p = (h >= 12) ? "pm" : "am";
  1127. h = (h > 12) ? h - 12 : h;
  1128. var output = '';
  1129. output += '<select id="h_' + this.id + '" class="timepicker">';
  1130. for (var hr in hrs){
  1131. output += '<option value="' + pad(hrs[hr]) + '"';
  1132. if(parseInt(hrs[hr],10) == h || (parseInt(hrs[hr],10) == 12 && h == 0)) {
  1133. output += ' selected';
  1134. }
  1135. output += '>' + pad(hrs[hr]) + '</option>';
  1136. }
  1137. output += '</select>';
  1138. output += '<select id="m_' + this.id + '" class="timepicker">';
  1139. for (var mn in mins){
  1140. output += '<option value="' + pad(mins[mn]) + '"';
  1141. if(parseInt(mins[mn],10) == m) output += ' selected';
  1142. output += '>' + pad(mins[mn]) + '</option>';
  1143. }
  1144. output += '</select>';
  1145. output += '<select id="p_' + this.id + '" class="timepicker">';
  1146. for(var pp in ap){
  1147. output += '<option value="' + ap[pp] + '"';
  1148. if(ap[pp] == p) output += ' selected';
  1149. output += '>' + ap[pp] + '</option>';
  1150. }
  1151. output += '</select>';
  1152. $(this).after(output);
  1153. var field = this;
  1154. $(this).siblings('select.timepicker').change(function() {
  1155. var h = parseInt(jQuery('#h_'+field.id).val(),10);
  1156. var m = parseInt($('#m_' + field.id).val(),10);
  1157. var p = $('#p_' + field.id).val();
  1158. if (p == "am") {
  1159. if (h == 12) {
  1160. h = 0;
  1161. }
  1162. } else if (p == "pm") {
  1163. if (h < 12) {
  1164. h += 12;
  1165. }
  1166. }
  1167. var d = new Date();
  1168. d.setHours(h);
  1169. d.setMinutes(m);
  1170. $(field).val(d.toUTCString());
  1171. }).change();
  1172. });
  1173. return this;
  1174. };
  1175. jQuery.fn.daypicker = function() {
  1176. var days = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
  1177. this.each(function() {
  1178. var v = $(this).val();
  1179. if (!v) v = 0;
  1180. v = parseInt(v,10);
  1181. var output = "";
  1182. output += '<select id="d_' + this.id + '" class="daypicker">';
  1183. for (var i = 0; i < days.length; i++) {
  1184. output += '<option value="' + i + '"';
  1185. if (v == i) output += ' selected';
  1186. output += '>' + days[i] + '</option>';
  1187. }
  1188. output += '</select>';
  1189. $(this).after(output);
  1190. var field = this;
  1191. $(this).siblings('select.daypicker').change(function() {
  1192. $(field).val( $(this).val() );
  1193. }).change();
  1194. });
  1195. };
  1196. jQuery.fn.forceToggleClass = function(classNames, bOn) {
  1197. return this.each(function() {
  1198. jQuery(this)[ bOn ? "addClass" : "removeClass" ](classNames);
  1199. });
  1200. };
  1201. })(jQuery);
  1202. jQuery(function() {
  1203. // add in the time and day selects
  1204. jQuery('form#cfzt_zanneltools input.time').timepicker();
  1205. jQuery('form#cfzt_zanneltools input.day').daypicker();
  1206. // togglers
  1207. jQuery('.time_toggle .toggler').change(function() {
  1208. var theSelect = jQuery(this);
  1209. theSelect.parent('.time_toggle').forceToggleClass('active', theSelect.val() === "1");
  1210. }).change();
  1211. });
  1212. <?php
  1213. break;
  1214. case 'prototype':
  1215. ?>
  1216. function cfztTestLogin() {
  1217. var username = $('cfzt_zannel_username').value;
  1218. var password = $('cfzt_zannel_password').value;
  1219. var result = $('cfzt_login_test_result');
  1220. result.className = 'cfzt_login_result_wait';
  1221. result.innerHTML = '<?php _e('Testing...', 'zannel-tools'); ?>';
  1222. var cfztAjax = new Ajax.Updater(
  1223. result,
  1224. "<?php bloginfo('wpurl'); ?>/index.php",
  1225. {
  1226. method: "post",
  1227. parameters: "cfzt_action=cfzt_login_test&cfzt_zannel_username=" + username + "&cfzt_zannel_password=" + password,
  1228. onComplete: cfztTestLoginResult
  1229. }
  1230. );
  1231. }
  1232. function cfztTestLoginResult() {
  1233. $('cfzt_login_test_result').className = 'cfzt_login_result';
  1234. Fat.fade_element('cfzt_login_test_result');
  1235. }
  1236. <?php
  1237. break;
  1238. }
  1239. die();
  1240. break;
  1241. case 'cfzt_css_admin':
  1242. remove_action('shutdown', 'cfzt_ping_digests');
  1243. header("Content-Type: text/css");
  1244. ?>
  1245. #cfzt_zupdate_form {
  1246. margin: 0;
  1247. padding: 5px 0;
  1248. }
  1249. #cfzt_zupdate_form fieldset {
  1250. border: 0;
  1251. }
  1252. #cfzt_zupdate_form fieldset textarea {
  1253. width: 95%;
  1254. }
  1255. #cfzt_zupdate_form fieldset #cfzt_zupdate_submit {
  1256. float: right;
  1257. margin-right: 50px;
  1258. }
  1259. #cfzt_zupdate_form fieldset #cfzt_char_count {
  1260. color: #666;
  1261. }
  1262. #ak_readme {
  1263. height: 300px;
  1264. width: 95%;
  1265. }
  1266. #cfzt_zanneltools .options {
  1267. overflow: hidden;
  1268. border: none;
  1269. }
  1270. #cfzt_zanneltools .option {
  1271. overflow: hidden;
  1272. border-bottom: dashed 1px #ccc;
  1273. padding-bottom: 9px;
  1274. padding-top: 9px;
  1275. }
  1276. #cfzt_zanneltools .option label {
  1277. display: block;
  1278. float: left;
  1279. width: 200px;
  1280. margin-right: 24px;
  1281. text-align: right;
  1282. }
  1283. #cfzt_zanneltools .option span {
  1284. display: block;
  1285. float: left;
  1286. margin-left: 230px;
  1287. margin-top: 6px;
  1288. clear: left;
  1289. }
  1290. #cfzt_zanneltools select,
  1291. #cfzt_zanneltools input {
  1292. float: left;
  1293. display: block;
  1294. margin-right: 6px;
  1295. }
  1296. #cfzt_zanneltools p.submit {
  1297. overflow: hidden;
  1298. }
  1299. #cfzt_zanneltools .option span {
  1300. color: #666;
  1301. display: block;
  1302. }
  1303. #cfzt_zanneltools #cfzt_login_test_result {
  1304. display: inline;
  1305. padding: 3px;
  1306. }
  1307. #cfzt_zanneltools fieldset.options .option span.cfzt_login_result_wait {
  1308. background: #ffc;
  1309. }
  1310. #cfzt_zanneltools fieldset.options .option span.cfzt_login_result {
  1311. background: #CFEBF7;
  1312. color: #000;
  1313. }
  1314. #cfzt_zanneltools .timepicker,
  1315. #cfzt_zanneltools .daypicker {
  1316. display: none;
  1317. }
  1318. #cfzt_zanneltools .active .timepicker,
  1319. #cfzt_zanneltools .active .daypicker {
  1320. display: block
  1321. }
  1322. fieldset.experimental {
  1323. border: 2px solid #900;
  1324. padding: 10px;
  1325. }
  1326. fieldset.experimental legend {
  1327. color: #900;
  1328. font-weight: bold;
  1329. }
  1330. <?php
  1331. die();
  1332. break;
  1333. }
  1334. }
  1335. if (!empty($_POST['cfzt_action'])) {
  1336. switch($_POST['cfzt_action']) {
  1337. case 'cfzt_update_settings':
  1338. $cfzt->populate_settings();
  1339. $cfzt->update_settings();
  1340. wp_redirect(get_bloginfo('wpurl').'/wp-admin/options-general.php?page=zannel-tools.php&updated=true');
  1341. die();
  1342. break;
  1343. case 'cfzt_post_zupdate_sidebar':
  1344. if (!empty($_POST['cfzt_zupdate_text']) && current_user_can('publish_posts')) {
  1345. $zupdate = new cfzt_zupdate();
  1346. $zupdate->zupdate_description = stripslashes($_POST['cfzt_zupdate_text']);
  1347. if ($cfzt->do_zupdate($zupdate)) {
  1348. die(__('Update posted.', 'zannel-tools'));
  1349. }
  1350. else {
  1351. die(__('Update post failed.', 'zannel-tools'));
  1352. }
  1353. }
  1354. break;
  1355. case 'cfzt_post_zupdate_admin':
  1356. if (!empty($_POST['cfzt_zupdate_text']) && current_user_can('publish_posts')) {
  1357. $zupdate = new cfzt_zupdate();
  1358. $zupdate->zupdate_description = stripslashes($_POST['cfzt_zupdate_text']);
  1359. if ($cfzt->do_zupdate($zupdate)) {
  1360. wp_redirect(get_bloginfo('wpurl').'/wp-admin/post-new.php?page=zannel-tools.php&zupdate-posted=true');
  1361. }
  1362. else {
  1363. wp_die(__('Oops, your Update was not posted. Please check your username and password and that Zannel is up and running happily.', 'zannel-tools'));
  1364. }
  1365. die();
  1366. }
  1367. break;
  1368. case 'cfzt_login_test':
  1369. $test = @cfzt_login_test(
  1370. @stripslashes($_POST['cfzt_zannel_username'])
  1371. , @stripslashes($_POST['cfzt_zannel_password'])
  1372. );
  1373. die(__($test, 'zannel-tools'));
  1374. break;
  1375. }
  1376. }
  1377. }
  1378. add_action('init', 'cfzt_request_handler', 10);
  1379. function cfzt_admin_zupdate_form() {
  1380. global $cfzt;
  1381. if ( $_GET['zupdate-posted'] ) {
  1382. print('
  1383. <div id="message" class="updated fade">
  1384. <p>'.__('Update posted.', 'zannel-tools').'</p>
  1385. </div>
  1386. ');
  1387. }
  1388. print('
  1389. <div class="wrap" id="cfzt_write_zupdate">
  1390. ');
  1391. if (empty($cfzt->zannel_username) || empty($cfzt->zannel_password)) {
  1392. print('
  1393. <p>Please enter your <a href="http://zannel.com">Zannel</a> account information in your <a href="options-general.php?page=zannel-tools.php">Zannel Tools Options</a>.</p>
  1394. ');
  1395. }
  1396. else {
  1397. print('
  1398. <h2>'.__('Write Update', 'zannel-tools').'</h2>
  1399. <p>This will create a new \'Update\' in <a href="http://zannel.com">Zannel</a> using the account information in your <a href="options-general.php?page=zannel-tools.php">Zannel Tools Options</a>.</p>
  1400. '.cfzt_zupdate_form('textarea').'
  1401. ');
  1402. }
  1403. print('
  1404. </div>
  1405. ');
  1406. }
  1407. function cfzt_options_form() {
  1408. global $wpdb, $cfzt;
  1409. $categories = get_categories('hide_empty=0');
  1410. $cat_options = '';
  1411. foreach ($categories as $category) {
  1412. if ($category->term_id == $cfzt->blog_post_category) {
  1413. $selected = 'selected="selected"';
  1414. }
  1415. else {
  1416. $selected = '';
  1417. }
  1418. $cat_options .= "\n\t<option value='$category->term_id' $selected>$category->name</option>";
  1419. }
  1420. $authors = get_users_of_blog();
  1421. $author_options = '';
  1422. foreach ($authors as $user) {
  1423. $usero = new WP_User($user->user_id);
  1424. $author = $usero->data;
  1425. // Only list users who are allowed to publish
  1426. if (! $usero->has_cap('publish_posts')) {
  1427. continue;
  1428. }
  1429. if ($author->ID == $cfzt->blog_post_author) {
  1430. $selected = 'selected="selected"';
  1431. }
  1432. else {
  1433. $selected = '';
  1434. }
  1435. $author_options .= "\n\t<option value='$author->ID' $selected>$author->user_nicename</option>";
  1436. }
  1437. $js_libs = array(
  1438. 'jquery' => 'jQuery'
  1439. , 'prototype' => 'Prototype'
  1440. );
  1441. $js_lib_options = '';
  1442. foreach ($js_libs as $js_lib => $js_lib_display) {
  1443. if ($js_lib == $cfzt->js_lib) {
  1444. $selected = 'selected="selected"';
  1445. }
  1446. else {
  1447. $selected = '';
  1448. }
  1449. $js_lib_options .= "\n\t<option value='$js_lib' $selected>$js_lib_display</option>";
  1450. }
  1451. $digest_zupdate_orders = array(
  1452. 'ASC' => 'Oldest first (Chronological order)'
  1453. , 'DESC' => 'Newest first (Reverse-chronological order)'
  1454. );
  1455. $digest_zupdate_order_options = '';
  1456. foreach ($digest_zupdate_orders as $digest_zupdate_order => $digest_zupdate_order_display) {
  1457. if ($digest_zupdate_order == $cfzt->digest_zupdate_order) {
  1458. $selected = 'selected="selected"';
  1459. }
  1460. else {
  1461. $selected = '';
  1462. }
  1463. $digest_zupdate_order_options .= "\n\t<option value='$digest_zupdate_order' $selected>$digest_zupdate_order_display</option>";
  1464. }
  1465. $yes_no = array(
  1466. 'create_blog_posts'
  1467. , 'create_digest'
  1468. , 'create_digest_weekly'
  1469. , 'notify_zannel'
  1470. , 'notify_zannel_default'
  1471. , 'zupdate_from_sidebar'
  1472. , 'give_cfzt_credit'
  1473. , 'exclude_reply_zupdates'
  1474. );
  1475. foreach ($yes_no as $key) {
  1476. $var = $key.'_options';
  1477. if ($cfzt->$key == '0') {
  1478. $$var = '
  1479. <option value="0" selected="selected">'.__('No', 'zannel-tools').'</option>
  1480. <option value="1">'.__('Yes', 'zannel-tools').'</option>
  1481. ';
  1482. }
  1483. else {
  1484. $$var = '
  1485. <option value="0">'.__('No', 'zannel-tools').'</option>
  1486. <option value="1" selected="selected">'.__('Yes', 'zannel-tools').'</option>
  1487. ';
  1488. }
  1489. }
  1490. if ( $_GET['zupdates-updated'] ) {
  1491. print('
  1492. <div id="message" class="updated fade">
  1493. <p>'.__('Zannel Updates updated.', 'zannel-tools').'</p>
  1494. </div>
  1495. ');
  1496. }
  1497. if ( $_GET['zupdate-checking-reset'] ) {
  1498. print('
  1499. <div id="message" class="updated fade">
  1500. <p>'.__('Update checking has been reset.', 'zannel-tools').'</p>
  1501. </div>
  1502. ');
  1503. }
  1504. print('
  1505. <div class="wrap" id="cfzt_options_page">
  1506. <h2>'.__('Zannel Tools Options', 'zannel-tools').'</h2>
  1507. <form id="cfzt_zanneltools" name="cfzt_zanneltools" action="'.get_bloginfo('wpurl').'/wp-admin/options-general.php" method="post">
  1508. <input type="hidden" name="cfzt_action" value="cfzt_update_settings" />
  1509. <fieldset class="options">
  1510. <div class="option">
  1511. <label for="cfzt_zannel_username">'.__('Zannel Username', 'zannel-tools').'/'.__('Password', 'zannel-tools').'</label>
  1512. <input type="text" size="25" name="cfzt_zannel_username" id="cfzt_zannel_username" value="'.$cfzt->zannel_username.'" autocomplete="off" />
  1513. <input type="password" size="25" name="cfzt_zannel_password" id="cfzt_zannel_password" value="'.$cfzt->zannel_password.'" autocomplete="off" />
  1514. <input type="button" name="cfzt_login_test" id="cfzt_login_test" value="'.__('Test Login Info', 'zannel-tools').'" onclick="cfztTestLogin(); return false;" />
  1515. <span id="cfzt_login_test_result"></span>
  1516. </div>
  1517. <div class="option">
  1518. <label for="cfzt_notify_zannel">'.__('Enable option to create a Zannel Update when you post in your blog?', 'zannel-tools').'</label>
  1519. <select name="cfzt_notify_zannel" id="cfzt_notify_zannel">'.$notify_zannel_options.'</select>
  1520. </div>
  1521. <div class="option">
  1522. <label for="cfzt_notify_zannel_default">'.__('Set this on by default?', 'zannel-tools').'</label>
  1523. <select name="cfzt_notify_zannel_default" id="cfzt_notify_zannel_default">'.$notify_zannel_default_options.'</select>
  1524. </div>
  1525. <div class="option">
  1526. <label for="cfzt_create_blog_posts">'.__('Create a blog post from each of your Zannel Updates?', 'zannel-tools').'</label>
  1527. <select name="cfzt_create_blog_posts" id="cfzt_create_blog_posts">'.$create_blog_posts_options.'</select>
  1528. </div>
  1529. <div class="option">
  1530. <label for="cfzt_default_post_title">'.__('If Zannel Update is just a pic or video, what should the title of the post be?', 'zannel-tools').'</label>
  1531. <input type="text" name="cfzt_default_post_title" id="cfzt_default_post_title" value="'.get_option('cfzt_default_post_title').'" />
  1532. </div>
  1533. <div class="option time_toggle">
  1534. <label>'.__('Create a daily digest blog post from your Zannel Updates?', 'zannel-tools').'</label>
  1535. <select name="cfzt_create_digest" class="toggler">'.$create_digest_options.'</select>
  1536. <input type="hidden" class="time" id="cfzt_digest_daily_time" name="cfzt_digest_daily_time" value="'.$cfzt->digest_daily_time.'" />
  1537. </div>
  1538. <div class="option">
  1539. <label for="cfzt_digest_title">'.__('Title for daily digest posts:', 'zannel-tools').'</label>
  1540. <input type="text" size="30" name="cfzt_digest_title" id="cfzt_digest_title" value="'.$cfzt->digest_title.'" />
  1541. <span>'.__('Include %s where you want the date. Example: Updates on %s', 'zannel-tools').'</span>
  1542. </div>
  1543. <div class="option time_toggle">
  1544. <label>'.__('Create a weekly digest blog post from your Zannel Updates?', 'zannel-tools').'</label>
  1545. <select name="cfzt_create_digest_weekly" class="toggler">'.$create_digest_weekly_options.'</select>
  1546. <input type="hidden" class="time" name="cfzt_digest_weekly_time" id="cfzt_digest_weekly_time" value="'.$cfzt->digest_weekly_time.'" />
  1547. <input type="hidden" class="day" name="cfzt_digest_weekly_day" value="'.$cfzt->digest_weekly_day.'" />
  1548. </div>
  1549. <div class="option">
  1550. <label for="cfzt_digest_title_weekly">'.__('Title for weekly digest posts:', 'zannel-tools').'</label>
  1551. <input type="text" size="30" name="cfzt_digest_title_weekly" id="cfzt_digest_title_weekly" value="'.$cfzt->digest_title_weekly.'" />
  1552. <span>'.__('Include %s where you want the date. Example: Updates on %s', 'zannel-tools').'</span>
  1553. </div>
  1554. <div class="option">
  1555. <label for="cfzt_digest_zupdate_order">'.__('Order of Zannel Updates in digest?', 'zannel-tools').'</label>
  1556. <select name="cfzt_digest_zupdate_order" id="cfzt_digest_zupdate_order">'.$digest_zupdate_order_options.'</select>
  1557. </div>
  1558. <div class="option">
  1559. <label for="cfzt_blog_post_category">'.__('Category for Zannel Update posts:', 'zannel-tools').'</label>
  1560. <select name="cfzt_blog_post_category" id="cfzt_blog_post_category">'.$cat_options.'</select>
  1561. </div>
  1562. <div class="option">
  1563. <label for="cfzt_blog_post_tags">'.__('Tag(s) for your Zannel Update posts:', 'zannel-tools').'</label>
  1564. <input name="cfzt_blog_post_tags" id="cfzt_blog_post_tags" value="'.$cfzt->blog_post_tags.'">
  1565. <span>'._('Separate multiple tags with commas. Example: updates, zannel').'</span>
  1566. </div>
  1567. <div class="option">
  1568. <label for="cfzt_blog_post_author">'.__('Author for Zannel Update posts:', 'zannel-tools').'</label>
  1569. <select name="cfzt_blog_post_author" id="cfzt_blog_post_author">'.$author_options.'</select>
  1570. </div>
  1571. <div class="option">
  1572. <label for="cfzt_exclude_reply_zupdates">'.__('Exclude @reply updates in your sidebar, digests and created blog posts?', 'zannel-tools').'</label>
  1573. <select name="cfzt_exclude_reply_zupdates" id="cfzt_exclude_reply_zupdates">'.$exclude_reply_zupdates_options.'</select>
  1574. </div>
  1575. <div class="option">
  1576. <label for="cfzt_sidebar_zupdate_count">'.__('Zannel Updates to show in sidebar:', 'zannel-tools').'</label>
  1577. <input type="text" size="3" name="cfzt_sidebar_zupdate_count" id="cfzt_sidebar_zupdate_count" value="'.$cfzt->sidebar_zupdate_count.'" />
  1578. <span>'.__('Numbers only please.', 'zannel-tools').'</span>
  1579. </div>
  1580. <div class="option">
  1581. <label for="cfzt_zupdate_from_sidebar">'.__('Create Zannel Updates from your sidebar?', 'zannel-tools').'</label>
  1582. <select name="cfzt_zupdate_from_sidebar" id="cfzt_zupdate_from_sidebar">'.$zupdate_from_sidebar_options.'</select>
  1583. </div>
  1584. <div class="option">
  1585. <label for="cfzt_js_lib">'.__('JS Library to use?', 'zannel-tools').'</label>
  1586. <select name="cfzt_js_lib" id="cfzt_js_lib">'.$js_lib_options.'</select>
  1587. </div>
  1588. <div class="option">
  1589. <label for="cfzt_give_cfzt_credit">'.__('Give Zannel Tools credit?', 'zannel-tools').'</label>
  1590. <select name="cfzt_give_cfzt_credit" id="cfzt_give_cfzt_credit">'.$give_cfzt_credit_options.'</select>
  1591. </div>
  1592. </fieldset>
  1593. <p class="submit">
  1594. <input type="submit" name="submit" value="'.__('Update Zannel Tools Options', 'zannel-tools').'" />
  1595. </p>
  1596. </form>
  1597. <h2>'.__('Update Zannel Updates', 'zannel-tools').'</h2>
  1598. <form name="cfzt_zanneltools_updatezupdates" action="'.get_bloginfo('wpurl').'/wp-admin/options-general.php" method="get">
  1599. <p>'.__('Use this button to manually refresh your Zannel Updates.', 'zannel-tools').'</p>
  1600. <p class="submit">
  1601. <input type="submit" name="submit-button" value="'.__('Refresh Updates', 'zannel-tools').'" />
  1602. <input type="submit" name="reset-button" value="'.__('Reset Update Checking', 'zannel-tools').'" onclick="document.getElementById(\'cfzt_action_2\').value = \'cfzt_reset_zupdate_checking\';" />
  1603. <input type="hidden" name="cfzt_action" id="cfzt_action_2" value="cfzt_update_zupdates" />
  1604. </p>
  1605. </form>
  1606. </div>
  1607. ');
  1608. }
  1609. function cfzt_post_options() {
  1610. global $cfzt, $post;
  1611. if ($cfzt->notify_zannel) {
  1612. echo '<div class="postbox">
  1613. <h3>Zannel Tools</h3>
  1614. <div class="inside">
  1615. <p>Notify Zannel about this post?
  1616. ';
  1617. if (get_post_meta($post->ID, 'cfzt_notify_zannel', true) == 'no' || !$cfzt->notify_zannel_default) {
  1618. $yes = '';
  1619. $no = 'checked="checked"';
  1620. }
  1621. else {
  1622. $yes = 'checked="checked"';
  1623. $no = '';
  1624. }
  1625. echo '
  1626. <input type="radio" name="cfzt_notify_zannel" id="cfzt_notify_zannel_yes" value="yes" '.$yes.' /> <label for="cfzt_notify_zannel_yes">Yes</label>&nbsp;&nbsp;
  1627. <input type="radio" name="cfzt_notify_zannel" id="cfzt_notify_zannel_no" value="no" '.$no.' /> <label for="cfzt_notify_zannel_no">No</label>
  1628. ';
  1629. echo '</p>
  1630. </div><!--.inside-->
  1631. </div><!--.postbox-->
  1632. ';
  1633. }
  1634. }
  1635. add_action('edit_form_advanced', 'cfzt_post_options');
  1636. function cfzt_store_post_options($post_id, $post = false) {
  1637. global $cfzt;
  1638. if (!$post || $post->post_type == 'revision') {
  1639. return;
  1640. }
  1641. if ((!empty($_POST['cfzt_notify_zannel']) && $_POST['cfzt_notify_zannel'] == "yes") || (empty($_POST['cfzt_notify_zannel']) && $cfzt->notify_zannel_default)) {
  1642. $notify = 'yes';
  1643. }
  1644. else {
  1645. $notify = 'no';
  1646. }
  1647. if (!update_post_meta($post_id, 'cfzt_notify_zannel', $notify)) {
  1648. add_post_meta($post_id, 'cfzt_notify_zannel', $notify);
  1649. }
  1650. }
  1651. add_action('draft_post', 'cfzt_store_post_options', 1, 2);
  1652. add_action('publish_post', 'cfzt_store_post_options', 1, 2);
  1653. add_action('save_post', 'cfzt_store_post_options', 1, 2);
  1654. function cfzt_menu_items() {
  1655. if (current_user_can('manage_options')) {
  1656. add_options_page(
  1657. __('Zannel Tools Options', 'zannel-tools')
  1658. , __('Zannel Tools', 'zannel-tools')
  1659. , 10
  1660. , basename(__FILE__)
  1661. , 'cfzt_options_form'
  1662. );
  1663. }
  1664. if (current_user_can('publish_posts')) {
  1665. add_submenu_page(
  1666. 'post-new.php'
  1667. , __('New Update', 'zannel-tools')
  1668. , __('Zannel Update', 'zannel-tools')
  1669. , 10
  1670. , basename(__FILE__)
  1671. , 'cfzt_admin_zupdate_form'
  1672. );
  1673. }
  1674. }
  1675. add_action('admin_menu', 'cfzt_menu_items');
  1676. function cfzt_plugin_action_links($links, $file) {
  1677. $plugin_file = basename(__FILE__);
  1678. if ($file == $plugin_file) {
  1679. $settings_link = '<a href="options-general.php?page='.$plugin_file.'">'.__('Settings', 'zannel-tools').'</a>';
  1680. array_unshift($links, $settings_link);
  1681. }
  1682. return $links;
  1683. }
  1684. add_filter('plugin_action_links', 'cfzt_plugin_action_links', 10, 2);
  1685. if (!function_exists('trim_add_elipsis')) {
  1686. function trim_add_elipsis($string, $limit = 100) {
  1687. if (strlen($string) > $limit) {
  1688. $string = substr($string, 0, $limit)."...";
  1689. }
  1690. return $string;
  1691. }
  1692. }
  1693. if (!function_exists('ak_gmmktime')) {
  1694. function ak_gmmktime() {
  1695. return gmmktime() - get_option('gmt_offset') * 3600;
  1696. }
  1697. }
  1698. /**
  1699. based on: http://www.gyford.com/phil/writing/2006/12/02/quick_twitter.php
  1700. * Returns a relative date, eg "4 hrs ago".
  1701. *
  1702. * Assumes the passed-in can be parsed by strtotime.
  1703. * Precision could be one of:
  1704. * 1 5 hours, 3 minutes, 2 seconds ago (not yet implemented).
  1705. * 2 5 hours, 3 minutes
  1706. * 3 5 hours
  1707. *
  1708. * This is all a little overkill, but copied from other places I've used it.
  1709. * Also superfluous, now I've noticed that the Zannel API includes something
  1710. * similar, but this version is more accurate and less verbose.
  1711. *
  1712. * @access private.
  1713. * @param string date In a format parseable by strtotime().
  1714. * @param integer precision
  1715. * @return string
  1716. */
  1717. function cfzt_relativeTime ($date, $precision=2)
  1718. {
  1719. $now = time();
  1720. /*$time = gmmktime(
  1721. substr($date, 11, 2)
  1722. , substr($date, 14, 2)
  1723. , substr($date, 17, 2)
  1724. , substr($date, 5, 2)
  1725. , substr($date, 8, 2)
  1726. , substr($date, 0, 4)
  1727. );
  1728. $time = strtotime(date('Y-m-d H:i:s', $time));*/
  1729. $time = strtotime($date);
  1730. $diff = $now - $time;
  1731. $months = floor($diff/2419200);
  1732. $diff -= $months * 2419200;
  1733. $weeks = floor($diff/604800);
  1734. $diff -= $weeks*604800;
  1735. $days = floor($diff/86400);
  1736. $diff -= $days * 86400;
  1737. $hours = floor($diff/3600);
  1738. $diff -= $hours * 3600;
  1739. $minutes = floor($diff/60);
  1740. $diff -= $minutes * 60;
  1741. $seconds = $diff;
  1742. if ($months > 0) {
  1743. return date('Y-m-d', $time);
  1744. } else {
  1745. $relative_date = '';
  1746. if ($weeks > 0) {
  1747. // Weeks and days
  1748. $relative_date .= ($relative_date?', ':'').$weeks.' week'.($weeks>1?'s':'');
  1749. if ($precision <= 2) {
  1750. $relative_date .= $days>0?($relative_date?', ':'').$days.' day'.($days>1?'s':''):'';
  1751. if ($precision == 1) {
  1752. $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hr'.($hours>1?'s':''):'';
  1753. }
  1754. }
  1755. } elseif ($days > 0) {
  1756. // days and hours
  1757. $relative_date .= ($relative_date?', ':'').$days.' day'.($days>1?'s':'');
  1758. if ($precision <= 2) {
  1759. $relative_date .= $hours>0?($relative_date?', ':'').$hours.' hr'.($hours>1?'s':''):'';
  1760. if ($precision == 1) {
  1761. $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':''):'';
  1762. }
  1763. }
  1764. } elseif ($hours > 0) {
  1765. // hours and minutes
  1766. $relative_date .= ($relative_date?', ':'').$hours.' hr'.($hours>1?'s':'');
  1767. if ($precision <= 2) {
  1768. $relative_date .= $minutes>0?($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':''):'';
  1769. if ($precision == 1) {
  1770. $relative_date .= $seconds>0?($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':''):'';
  1771. }
  1772. }
  1773. } elseif ($minutes > 0) {
  1774. // minutes only
  1775. $relative_date .= ($relative_date?', ':'').$minutes.' min'.($minutes>1?'s':'');
  1776. if ($precision == 1) {
  1777. $relative_date .= $seconds>0?($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':''):'';
  1778. }
  1779. } else {
  1780. // seconds only
  1781. $relative_date .= ($relative_date?', ':'').$seconds.' sec'.($seconds>1?'s':'');
  1782. }
  1783. }
  1784. // Return relative date and add proper verbiage
  1785. return sprintf(__('%s ago', 'zannel-tools'), $relative_date);
  1786. }
  1787. if (!class_exists('Services_JSON')) {
  1788. // PEAR JSON class
  1789. /**
  1790. * Converts to and from JSON format.
  1791. *
  1792. * JSON (JavaScript Object Notation) is a lightweight data-interchange
  1793. * format. It is easy for humans to read and write. It is easy for machines
  1794. * to parse and generate. It is based on a subset of the JavaScript
  1795. * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
  1796. * This feature can also be found in Python. JSON is a text format that is
  1797. * completely language independent but uses conventions that are familiar
  1798. * to programmers of the C-family of languages, including C, C++, C#, Java,
  1799. * JavaScript, Perl, TCL, and many others. These properties make JSON an
  1800. * ideal data-interchange language.
  1801. *
  1802. * This package provides a simple encoder and decoder for JSON notation. It
  1803. * is intended for use with client-side Javascript applications that make
  1804. * use of HTTPRequest to perform server communication functions - data can
  1805. * be encoded into JSON notation for use in a client-side javascript, or
  1806. * decoded from incoming Javascript requests. JSON format is native to
  1807. * Javascript, and can be directly eval()'ed with no further parsing
  1808. * overhead
  1809. *
  1810. * All strings should be in ASCII or UTF-8 format!
  1811. *
  1812. * LICENSE: Redistribution and use in source and binary forms, with or
  1813. * without modification, are permitted provided that the following
  1814. * conditions are met: Redistributions of source code must retain the
  1815. * above copyright notice, this list of conditions and the following
  1816. * disclaimer. Redistributions in binary form must reproduce the above
  1817. * copyright notice, this list of conditions and the following disclaimer
  1818. * in the documentation and/or other materials provided with the
  1819. * distribution.
  1820. *
  1821. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  1822. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  1823. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  1824. * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  1825. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  1826. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  1827. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  1828. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  1829. * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  1830. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  1831. * DAMAGE.
  1832. *
  1833. * @category
  1834. * @package Services_JSON
  1835. * @author Michal Migurski <mike-json@teczno.com>
  1836. * @author Matt Knapp <mdknapp[at]gmail[dot]com>
  1837. * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
  1838. * @copyright 2005 Michal Migurski
  1839. * @version CVS: $Id: zannel-tools.php 42 2011-09-19 20:39:32Z arwinh $
  1840. * @license http://www.opensource.org/licenses/bsd-license.php
  1841. * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
  1842. */
  1843. /**
  1844. * Marker constant for Services_JSON::decode(), used to flag stack state
  1845. */
  1846. define('SERVICES_JSON_SLICE', 1);
  1847. /**
  1848. * Marker constant for Services_JSON::decode(), used to flag stack state
  1849. */
  1850. define('SERVICES_JSON_IN_STR', 2);
  1851. /**
  1852. * Marker constant for Services_JSON::decode(), used to flag stack state
  1853. */
  1854. define('SERVICES_JSON_IN_ARR', 3);
  1855. /**
  1856. * Marker constant for Services_JSON::decode(), used to flag stack state
  1857. */
  1858. define('SERVICES_JSON_IN_OBJ', 4);
  1859. /**
  1860. * Marker constant for Services_JSON::decode(), used to flag stack state
  1861. */
  1862. define('SERVICES_JSON_IN_CMT', 5);
  1863. /**
  1864. * Behavior switch for Services_JSON::decode()
  1865. */
  1866. define('SERVICES_JSON_LOOSE_TYPE', 16);
  1867. /**
  1868. * Behavior switch for Services_JSON::decode()
  1869. */
  1870. define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
  1871. /**
  1872. * Converts to and from JSON format.
  1873. *
  1874. * Brief example of use:
  1875. *
  1876. * <code>
  1877. * // create a new instance of Services_JSON
  1878. * $json = new Services_JSON();
  1879. *
  1880. * // convert a complexe value to JSON notation, and send it to the browser
  1881. * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
  1882. * $output = $json->encode($value);
  1883. *
  1884. * print($output);
  1885. * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
  1886. *
  1887. * // accept incoming POST data, assumed to be in JSON notation
  1888. * $input = file_get_contents('php://input', 1000000);
  1889. * $value = $json->decode($input);
  1890. * </code>
  1891. */
  1892. class Services_JSON
  1893. {
  1894. /**
  1895. * constructs a new JSON instance
  1896. *
  1897. * @param int $use object behavior flags; combine with boolean-OR
  1898. *
  1899. * possible values:
  1900. * - SERVICES_JSON_LOOSE_TYPE: loose typing.
  1901. * "{...}" syntax creates associative arrays
  1902. * instead of objects in decode().
  1903. * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
  1904. * Values which can't be encoded (e.g. resources)
  1905. * appear as NULL instead of throwing errors.
  1906. * By default, a deeply-nested resource will
  1907. * bubble up with an error, so all return values
  1908. * from encode() should be checked with isError()
  1909. */
  1910. function Services_JSON($use = 0)
  1911. {
  1912. $this->use = $use;
  1913. }
  1914. /**
  1915. * convert a string from one UTF-16 char to one UTF-8 char
  1916. *
  1917. * Normally should be handled by mb_convert_encoding, but
  1918. * provides a slower PHP-only method for installations
  1919. * that lack the multibye string extension.
  1920. *
  1921. * @param string $utf16 UTF-16 character
  1922. * @return string UTF-8 character
  1923. * @access private
  1924. */
  1925. function utf162utf8($utf16)
  1926. {
  1927. // oh please oh please oh please oh please oh please
  1928. if(function_exists('mb_convert_encoding')) {
  1929. return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
  1930. }
  1931. $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
  1932. switch(true) {
  1933. case ((0x7F & $bytes) == $bytes):
  1934. // this case should never be reached, because we are in ASCII range
  1935. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1936. return chr(0x7F & $bytes);
  1937. case (0x07FF & $bytes) == $bytes:
  1938. // return a 2-byte UTF-8 character
  1939. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1940. return chr(0xC0 | (($bytes >> 6) & 0x1F))
  1941. . chr(0x80 | ($bytes & 0x3F));
  1942. case (0xFFFF & $bytes) == $bytes:
  1943. // return a 3-byte UTF-8 character
  1944. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1945. return chr(0xE0 | (($bytes >> 12) & 0x0F))
  1946. . chr(0x80 | (($bytes >> 6) & 0x3F))
  1947. . chr(0x80 | ($bytes & 0x3F));
  1948. }
  1949. // ignoring UTF-32 for now, sorry
  1950. return '';
  1951. }
  1952. /**
  1953. * convert a string from one UTF-8 char to one UTF-16 char
  1954. *
  1955. * Normally should be handled by mb_convert_encoding, but
  1956. * provides a slower PHP-only method for installations
  1957. * that lack the multibye string extension.
  1958. *
  1959. * @param string $utf8 UTF-8 character
  1960. * @return string UTF-16 character
  1961. * @access private
  1962. */
  1963. function utf82utf16($utf8)
  1964. {
  1965. // oh please oh please oh please oh please oh please
  1966. if(function_exists('mb_convert_encoding')) {
  1967. return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
  1968. }
  1969. switch(strlen($utf8)) {
  1970. case 1:
  1971. // this case should never be reached, because we are in ASCII range
  1972. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1973. return $utf8;
  1974. case 2:
  1975. // return a UTF-16 character from a 2-byte UTF-8 char
  1976. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1977. return chr(0x07 & (ord($utf8{0}) >> 2))
  1978. . chr((0xC0 & (ord($utf8{0}) << 6))
  1979. | (0x3F & ord($utf8{1})));
  1980. case 3:
  1981. // return a UTF-16 character from a 3-byte UTF-8 char
  1982. // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  1983. return chr((0xF0 & (ord($utf8{0}) << 4))
  1984. | (0x0F & (ord($utf8{1}) >> 2)))
  1985. . chr((0xC0 & (ord($utf8{1}) << 6))
  1986. | (0x7F & ord($utf8{2})));
  1987. }
  1988. // ignoring UTF-32 for now, sorry
  1989. return '';
  1990. }
  1991. /**
  1992. * encodes an arbitrary variable into JSON format
  1993. *
  1994. * @param mixed $var any number, boolean, string, array, or object to be encoded.
  1995. * see argument 1 to Services_JSON() above for array-parsing behavior.
  1996. * if var is a strng, note that encode() always expects it
  1997. * to be in ASCII or UTF-8 format!
  1998. *
  1999. * @return mixed JSON string representation of input var or an error if a problem occurs
  2000. * @access public
  2001. */
  2002. function encode($var)
  2003. {
  2004. switch (gettype($var)) {
  2005. case 'boolean':
  2006. return $var ? 'true' : 'false';
  2007. case 'NULL':
  2008. return 'null';
  2009. case 'integer':
  2010. return (int) $var;
  2011. case 'double':
  2012. case 'float':
  2013. return (float) $var;
  2014. case 'string':
  2015. // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
  2016. $ascii = '';
  2017. $strlen_var = strlen($var);
  2018. /*
  2019. * Iterate over every character in the string,
  2020. * escaping with a slash or encoding to UTF-8 where necessary
  2021. */
  2022. for ($c = 0; $c < $strlen_var; ++$c) {
  2023. $ord_var_c = ord($var{$c});
  2024. switch (true) {
  2025. case $ord_var_c == 0x08:
  2026. $ascii .= '\b';
  2027. break;
  2028. case $ord_var_c == 0x09:
  2029. $ascii .= '\t';
  2030. break;
  2031. case $ord_var_c == 0x0A:
  2032. $ascii .= '\n';
  2033. break;
  2034. case $ord_var_c == 0x0C:
  2035. $ascii .= '\f';
  2036. break;
  2037. case $ord_var_c == 0x0D:
  2038. $ascii .= '\r';
  2039. break;
  2040. case $ord_var_c == 0x22:
  2041. case $ord_var_c == 0x2F:
  2042. case $ord_var_c == 0x5C:
  2043. // double quote, slash, slosh
  2044. $ascii .= '\\'.$var{$c};
  2045. break;
  2046. case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
  2047. // characters U-00000000 - U-0000007F (same as ASCII)
  2048. $ascii .= $var{$c};
  2049. break;
  2050. case (($ord_var_c & 0xE0) == 0xC0):
  2051. // characters U-00000080 - U-000007FF, mask 110XXXXX
  2052. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2053. $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
  2054. $c += 1;
  2055. $utf16 = $this->utf82utf16($char);
  2056. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  2057. break;
  2058. case (($ord_var_c & 0xF0) == 0xE0):
  2059. // characters U-00000800 - U-0000FFFF, mask 1110XXXX
  2060. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2061. $char = pack('C*', $ord_var_c,
  2062. ord($var{$c + 1}),
  2063. ord($var{$c + 2}));
  2064. $c += 2;
  2065. $utf16 = $this->utf82utf16($char);
  2066. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  2067. break;
  2068. case (($ord_var_c & 0xF8) == 0xF0):
  2069. // characters U-00010000 - U-001FFFFF, mask 11110XXX
  2070. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2071. $char = pack('C*', $ord_var_c,
  2072. ord($var{$c + 1}),
  2073. ord($var{$c + 2}),
  2074. ord($var{$c + 3}));
  2075. $c += 3;
  2076. $utf16 = $this->utf82utf16($char);
  2077. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  2078. break;
  2079. case (($ord_var_c & 0xFC) == 0xF8):
  2080. // characters U-00200000 - U-03FFFFFF, mask 111110XX
  2081. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2082. $char = pack('C*', $ord_var_c,
  2083. ord($var{$c + 1}),
  2084. ord($var{$c + 2}),
  2085. ord($var{$c + 3}),
  2086. ord($var{$c + 4}));
  2087. $c += 4;
  2088. $utf16 = $this->utf82utf16($char);
  2089. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  2090. break;
  2091. case (($ord_var_c & 0xFE) == 0xFC):
  2092. // characters U-04000000 - U-7FFFFFFF, mask 1111110X
  2093. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2094. $char = pack('C*', $ord_var_c,
  2095. ord($var{$c + 1}),
  2096. ord($var{$c + 2}),
  2097. ord($var{$c + 3}),
  2098. ord($var{$c + 4}),
  2099. ord($var{$c + 5}));
  2100. $c += 5;
  2101. $utf16 = $this->utf82utf16($char);
  2102. $ascii .= sprintf('\u%04s', bin2hex($utf16));
  2103. break;
  2104. }
  2105. }
  2106. return '"'.$ascii.'"';
  2107. case 'array':
  2108. /*
  2109. * As per JSON spec if any array key is not an integer
  2110. * we must treat the the whole array as an object. We
  2111. * also try to catch a sparsely populated associative
  2112. * array with numeric keys here because some JS engines
  2113. * will create an array with empty indexes up to
  2114. * max_index which can cause memory issues and because
  2115. * the keys, which may be relevant, will be remapped
  2116. * otherwise.
  2117. *
  2118. * As per the ECMA and JSON specification an object may
  2119. * have any string as a property. Unfortunately due to
  2120. * a hole in the ECMA specification if the key is a
  2121. * ECMA reserved word or starts with a digit the
  2122. * parameter is only accessible using ECMAScript's
  2123. * bracket notation.
  2124. */
  2125. // treat as a JSON object
  2126. if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
  2127. $properties = array_map(array($this, 'name_value'),
  2128. array_keys($var),
  2129. array_values($var));
  2130. foreach($properties as $property) {
  2131. if(Services_JSON::isError($property)) {
  2132. return $property;
  2133. }
  2134. }
  2135. return '{' . join(',', $properties) . '}';
  2136. }
  2137. // treat it like a regular array
  2138. $elements = array_map(array($this, 'encode'), $var);
  2139. foreach($elements as $element) {
  2140. if(Services_JSON::isError($element)) {
  2141. return $element;
  2142. }
  2143. }
  2144. return '[' . join(',', $elements) . ']';
  2145. case 'object':
  2146. $vars = get_object_vars($var);
  2147. $properties = array_map(array($this, 'name_value'),
  2148. array_keys($vars),
  2149. array_values($vars));
  2150. foreach($properties as $property) {
  2151. if(Services_JSON::isError($property)) {
  2152. return $property;
  2153. }
  2154. }
  2155. return '{' . join(',', $properties) . '}';
  2156. default:
  2157. return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
  2158. ? 'null'
  2159. : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
  2160. }
  2161. }
  2162. /**
  2163. * array-walking function for use in generating JSON-formatted name-value pairs
  2164. *
  2165. * @param string $name name of key to use
  2166. * @param mixed $value reference to an array element to be encoded
  2167. *
  2168. * @return string JSON-formatted name-value pair, like '"name":value'
  2169. * @access private
  2170. */
  2171. function name_value($name, $value)
  2172. {
  2173. $encoded_value = $this->encode($value);
  2174. if(Services_JSON::isError($encoded_value)) {
  2175. return $encoded_value;
  2176. }
  2177. return $this->encode(strval($name)) . ':' . $encoded_value;
  2178. }
  2179. /**
  2180. * reduce a string by removing leading and trailing comments and whitespace
  2181. *
  2182. * @param $str string string value to strip of comments and whitespace
  2183. *
  2184. * @return string string value stripped of comments and whitespace
  2185. * @access private
  2186. */
  2187. function reduce_string($str)
  2188. {
  2189. $str = preg_replace(array(
  2190. // eliminate single line comments in '// ...' form
  2191. '#^\s*//(.+)$#m',
  2192. // eliminate multi-line comments in '/* ... */' form, at start of string
  2193. '#^\s*/\*(.+)\*/#Us',
  2194. // eliminate multi-line comments in '/* ... */' form, at end of string
  2195. '#/\*(.+)\*/\s*$#Us'
  2196. ), '', $str);
  2197. // eliminate extraneous space
  2198. return trim($str);
  2199. }
  2200. /**
  2201. * decodes a JSON string into appropriate variable
  2202. *
  2203. * @param string $str JSON-formatted string
  2204. *
  2205. * @return mixed number, boolean, string, array, or object
  2206. * corresponding to given JSON input string.
  2207. * See argument 1 to Services_JSON() above for object-output behavior.
  2208. * Note that decode() always returns strings
  2209. * in ASCII or UTF-8 format!
  2210. * @access public
  2211. */
  2212. function decode($str)
  2213. {
  2214. $str = $this->reduce_string($str);
  2215. switch (strtolower($str)) {
  2216. case 'true':
  2217. return true;
  2218. case 'false':
  2219. return false;
  2220. case 'null':
  2221. return null;
  2222. default:
  2223. $m = array();
  2224. if (is_numeric($str)) {
  2225. // Lookie-loo, it's a number
  2226. // This would work on its own, but I'm trying to be
  2227. // good about returning integers where appropriate:
  2228. // return (float)$str;
  2229. // Return float or int, as appropriate
  2230. return ((float)$str == (integer)$str)
  2231. ? (integer)$str
  2232. : (float)$str;
  2233. } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
  2234. // STRINGS RETURNED IN UTF-8 FORMAT
  2235. $delim = substr($str, 0, 1);
  2236. $chrs = substr($str, 1, -1);
  2237. $utf8 = '';
  2238. $strlen_chrs = strlen($chrs);
  2239. for ($c = 0; $c < $strlen_chrs; ++$c) {
  2240. $substr_chrs_c_2 = substr($chrs, $c, 2);
  2241. $ord_chrs_c = ord($chrs{$c});
  2242. switch (true) {
  2243. case $substr_chrs_c_2 == '\b':
  2244. $utf8 .= chr(0x08);
  2245. ++$c;
  2246. break;
  2247. case $substr_chrs_c_2 == '\t':
  2248. $utf8 .= chr(0x09);
  2249. ++$c;
  2250. break;
  2251. case $substr_chrs_c_2 == '\n':
  2252. $utf8 .= chr(0x0A);
  2253. ++$c;
  2254. break;
  2255. case $substr_chrs_c_2 == '\f':
  2256. $utf8 .= chr(0x0C);
  2257. ++$c;
  2258. break;
  2259. case $substr_chrs_c_2 == '\r':
  2260. $utf8 .= chr(0x0D);
  2261. ++$c;
  2262. break;
  2263. case $substr_chrs_c_2 == '\\"':
  2264. case $substr_chrs_c_2 == '\\\'':
  2265. case $substr_chrs_c_2 == '\\\\':
  2266. case $substr_chrs_c_2 == '\\/':
  2267. if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
  2268. ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
  2269. $utf8 .= $chrs{++$c};
  2270. }
  2271. break;
  2272. case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
  2273. // single, escaped unicode character
  2274. $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
  2275. . chr(hexdec(substr($chrs, ($c + 4), 2)));
  2276. $utf8 .= $this->utf162utf8($utf16);
  2277. $c += 5;
  2278. break;
  2279. case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
  2280. $utf8 .= $chrs{$c};
  2281. break;
  2282. case ($ord_chrs_c & 0xE0) == 0xC0:
  2283. // characters U-00000080 - U-000007FF, mask 110XXXXX
  2284. //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2285. $utf8 .= substr($chrs, $c, 2);
  2286. ++$c;
  2287. break;
  2288. case ($ord_chrs_c & 0xF0) == 0xE0:
  2289. // characters U-00000800 - U-0000FFFF, mask 1110XXXX
  2290. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2291. $utf8 .= substr($chrs, $c, 3);
  2292. $c += 2;
  2293. break;
  2294. case ($ord_chrs_c & 0xF8) == 0xF0:
  2295. // characters U-00010000 - U-001FFFFF, mask 11110XXX
  2296. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2297. $utf8 .= substr($chrs, $c, 4);
  2298. $c += 3;
  2299. break;
  2300. case ($ord_chrs_c & 0xFC) == 0xF8:
  2301. // characters U-00200000 - U-03FFFFFF, mask 111110XX
  2302. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2303. $utf8 .= substr($chrs, $c, 5);
  2304. $c += 4;
  2305. break;
  2306. case ($ord_chrs_c & 0xFE) == 0xFC:
  2307. // characters U-04000000 - U-7FFFFFFF, mask 1111110X
  2308. // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
  2309. $utf8 .= substr($chrs, $c, 6);
  2310. $c += 5;
  2311. break;
  2312. }
  2313. }
  2314. return $utf8;
  2315. } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
  2316. // array, or object notation
  2317. if ($str{0} == '[') {
  2318. $stk = array(SERVICES_JSON_IN_ARR);
  2319. $arr = array();
  2320. } else {
  2321. if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
  2322. $stk = array(SERVICES_JSON_IN_OBJ);
  2323. $obj = array();
  2324. } else {
  2325. $stk = array(SERVICES_JSON_IN_OBJ);
  2326. $obj = new stdClass();
  2327. }
  2328. }
  2329. array_push($stk, array('what' => SERVICES_JSON_SLICE,
  2330. 'where' => 0,
  2331. 'delim' => false));
  2332. $chrs = substr($str, 1, -1);
  2333. $chrs = $this->reduce_string($chrs);
  2334. if ($chrs == '') {
  2335. if (reset($stk) == SERVICES_JSON_IN_ARR) {
  2336. return $arr;
  2337. } else {
  2338. return $obj;
  2339. }
  2340. }
  2341. //print("\nparsing {$chrs}\n");
  2342. $strlen_chrs = strlen($chrs);
  2343. for ($c = 0; $c <= $strlen_chrs; ++$c) {
  2344. $top = end($stk);
  2345. $substr_chrs_c_2 = substr($chrs, $c, 2);
  2346. if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
  2347. // found a comma that is not inside a string, array, etc.,
  2348. // OR we've reached the end of the character list
  2349. $slice = substr($chrs, $top['where'], ($c - $top['where']));
  2350. array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
  2351. //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
  2352. if (reset($stk) == SERVICES_JSON_IN_ARR) {
  2353. // we are in an array, so just push an element onto the stack
  2354. array_push($arr, $this->decode($slice));
  2355. } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
  2356. // we are in an object, so figure
  2357. // out the property name and set an
  2358. // element in an associative array,
  2359. // for now
  2360. $parts = array();
  2361. if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  2362. // "name":value pair
  2363. $key = $this->decode($parts[1]);
  2364. $val = $this->decode($parts[2]);
  2365. if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
  2366. $obj[$key] = $val;
  2367. } else {
  2368. $obj->$key = $val;
  2369. }
  2370. } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
  2371. // name:value pair, where name is unquoted
  2372. $key = $parts[1];
  2373. $val = $this->decode($parts[2]);
  2374. if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
  2375. $obj[$key] = $val;
  2376. } else {
  2377. $obj->$key = $val;
  2378. }
  2379. }
  2380. }
  2381. } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
  2382. // found a quote, and we are not inside a string
  2383. array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
  2384. //print("Found start of string at {$c}\n");
  2385. } elseif (($chrs{$c} == $top['delim']) &&
  2386. ($top['what'] == SERVICES_JSON_IN_STR) &&
  2387. ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
  2388. // found a quote, we're in a string, and it's not escaped
  2389. // we know that it's not escaped becase there is _not_ an
  2390. // odd number of backslashes at the end of the string so far
  2391. array_pop($stk);
  2392. //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
  2393. } elseif (($chrs{$c} == '[') &&
  2394. in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
  2395. // found a left-bracket, and we are in an array, object, or slice
  2396. array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
  2397. //print("Found start of array at {$c}\n");
  2398. } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
  2399. // found a right-bracket, and we're in an array
  2400. array_pop($stk);
  2401. //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
  2402. } elseif (($chrs{$c} == '{') &&
  2403. in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
  2404. // found a left-brace, and we are in an array, object, or slice
  2405. array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
  2406. //print("Found start of object at {$c}\n");
  2407. } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
  2408. // found a right-brace, and we're in an object
  2409. array_pop($stk);
  2410. //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
  2411. } elseif (($substr_chrs_c_2 == '/*') &&
  2412. in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
  2413. // found a comment start, and we are in an array, object, or slice
  2414. array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
  2415. $c++;
  2416. //print("Found start of comment at {$c}\n");
  2417. } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
  2418. // found a comment end, and we're in one now
  2419. array_pop($stk);
  2420. $c++;
  2421. for ($i = $top['where']; $i <= $c; ++$i)
  2422. $chrs = substr_replace($chrs, ' ', $i, 1);
  2423. //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
  2424. }
  2425. }
  2426. if (reset($stk) == SERVICES_JSON_IN_ARR) {
  2427. return $arr;
  2428. } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
  2429. return $obj;
  2430. }
  2431. }
  2432. }
  2433. }
  2434. /**
  2435. * @todo Ultimately, this should just call PEAR::isError()
  2436. */
  2437. function isError($data, $code = null)
  2438. {
  2439. if (class_exists('pear')) {
  2440. return PEAR::isError($data, $code);
  2441. } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
  2442. is_subclass_of($data, 'services_json_error'))) {
  2443. return true;
  2444. }
  2445. return false;
  2446. }
  2447. }
  2448. if (class_exists('PEAR_Error')) {
  2449. class Services_JSON_Error extends PEAR_Error
  2450. {
  2451. function Services_JSON_Error($message = 'unknown error', $code = null,
  2452. $mode = null, $options = null, $userinfo = null)
  2453. {
  2454. parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
  2455. }
  2456. }
  2457. } else {
  2458. /**
  2459. * @todo Ultimately, this class shall be descended from PEAR_Error
  2460. */
  2461. class Services_JSON_Error
  2462. {
  2463. function Services_JSON_Error($message = 'unknown error', $code = null,
  2464. $mode = null, $options = null, $userinfo = null)
  2465. {
  2466. }
  2467. }
  2468. }
  2469. }
  2470. ?>