Пример моего кода на PHP... И не только.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
44KB

  1. <?php
  2. if ( ! defined( 'ABSPATH' ) ) exit;
  3. class ChiefRed {
  4. private static $initiated = false;
  5. public static function init()
  6. {
  7. if(!session_id()) {
  8. session_start();
  9. $_SESSION['starttime'] = (!isset($_SESSION['starttime'])) ? time() : $_SESSION['starttime'];
  10. }
  11. if ( ! self::$initiated ) {
  12. self::init_hooks();
  13. }
  14. }
  15. private static function init_hooks()
  16. {
  17. self::$initiated = true;
  18. add_action( 'rest_api_init',
  19. function () {
  20. register_rest_route( 'chiefred', '/sync(.*)',
  21. array(
  22. 'methods' => 'GET',
  23. 'callback' => array( 'ChiefRed', 'sync' ),
  24. )
  25. );
  26. register_rest_route( 'chiefred', '/canonical(.*)',
  27. array(
  28. 'methods' => 'GET',
  29. 'callback' => array( 'ChiefRed', 'canonical' ),
  30. )
  31. );
  32. register_rest_route( 'chiefred', '/was_useful(.*)',
  33. array(
  34. 'methods' => 'POST',
  35. 'callback' => array( 'ChiefRed', 'was_useful' ),
  36. )
  37. );
  38. }
  39. );
  40. add_filter( 'cron_schedules', [__CLASS__, 'add_every4hours_schedule'] );
  41. add_action( 'chiefred_synchronize', [__CLASS__, 'synchronize'] );
  42. add_action( 'chiefred_every4hours_synchronize', [__CLASS__, 'synchronize'] );
  43. add_action( 'wp_enqueue_scripts', [__CLASS__, 'load_resources'] );
  44. add_action( 'wp_head', [__CLASS__, 'add_article_headers'] );
  45. add_filter( 'the_content', [__CLASS__, 'add_article_components'] );
  46. }
  47. public static function add_every4hours_schedule( $schedules ) {
  48. $schedules['every4hours'] = array(
  49. 'interval' => 14400,
  50. 'display' => __('Every 4 hours')
  51. );
  52. return $schedules;
  53. }
  54. public static function load_resources()
  55. {
  56. $post = get_post();
  57. if ($post) {
  58. $article_id = get_post_meta($post->ID, '_chiefred_id', true);
  59. if ( $post && 'page' == $post->post_type && $article_id ) {
  60. $css_file = (file_exists(CHIEFRED_PLUGIN_DIR.'res/chiefred.css')) ? CHIEFRED_PLUGIN_URL.'res/chiefred.css' : CHIEFRED_PLUGIN_URL.'res/chiefred.default.css';
  61. wp_register_style( 'chiefred.css', $css_file, array(), CHIEFRED_VERSION );
  62. wp_enqueue_style( 'chiefred.css');
  63. $js_file = (file_exists(CHIEFRED_PLUGIN_DIR.'res/chiefred.js')) ? CHIEFRED_PLUGIN_URL.'res/chiefred.js' : CHIEFRED_PLUGIN_URL.'res/chiefred.default.js';
  64. wp_register_script( 'chiefred.js', $js_file, array('jquery'), CHIEFRED_VERSION );
  65. wp_enqueue_script( 'chiefred.js' );
  66. }
  67. }
  68. }
  69. public static function add_article_headers()
  70. {
  71. $post = get_post();
  72. if ($post) {
  73. $keywords = esc_attr(get_post_meta($post->ID, '_chiefred_keyword', true));
  74. $description = esc_attr(get_post_meta($post->ID, '_chiefred_description', true));
  75. if ( $post && 'page' == $post->post_type && $keywords ) {
  76. echo "<meta name=\"keywords\" content=\"{$keywords}\" />\n";
  77. }
  78. if ( $post && 'page' == $post->post_type && $description ) {
  79. echo "<meta name=\"description\" content=\"{$description}\" />\n";
  80. }
  81. }
  82. }
  83. public static function add_article_components($content)
  84. {
  85. $illustration_size = get_option('chiefred_illustration_size', 'medium');
  86. $illustration_class = get_option('chiefred_illustration_class');
  87. $illustration_link = get_option('chiefred_illustration_link');
  88. $illustration_link_class = get_option('chiefred_illustration_link_class');
  89. $illustration_link_rel = get_option('chiefred_illustration_link_rel');
  90. $illustration_link_target = get_option('chiefred_illustration_link_target');
  91. $dom = new DOMDocument('1.0', 'UTF-8');
  92. libxml_use_internal_errors(true);
  93. $post = get_post();
  94. $article = (object)[];
  95. $article->id = get_post_meta($post->ID, '_chiefred_id', true);
  96. if ( $post && 'page' == $post->post_type && $article->id ) {
  97. if ( get_option('chiefred_article_parent_link') && $post->post_parent ) {
  98. $article->parent = (object)[];
  99. $article->parent->href = wp_get_canonical_url($post->post_parent);
  100. $article->parent->title = get_the_title($post->post_parent);
  101. }
  102. if ( get_option('chiefred_article_creators') ) {
  103. $article->creators = [];
  104. $creators = json_decode(get_post_meta($post->ID, '_chiefred_creators', true));
  105. if(isset($creators->author)) {
  106. $article->creators[(is_array($creators->author)?$creators->author[0]:$creators->author)] = 'автор'; //обратная совместимость со старым форматом с массивом
  107. }
  108. if(isset($creators->editor)) {
  109. $article->creators[(is_array($creators->editor)?$creators->editor[0]:$creators->editor)] = 'редактор'; //обратная совместимость со старым форматом с массивом
  110. }
  111. if(isset($creators->illustrators)) foreach($creators->illustrators as $creator) {
  112. $article->creators[$creator] = (isset($article->creators[$creator]))?($article->creators[$creator].', иллюстрации'):'иллюстрации';
  113. }
  114. }
  115. $article->content = $content;
  116. $iquery = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_article_id&meta_value={$article->id}" );
  117. foreach ($iquery->posts as $i) {
  118. $attachment_image = wp_get_attachment_image_src($i->ID, $illustration_size);
  119. $src = $attachment_image[0];
  120. $href = wp_get_attachment_image_src($i->ID, 'full')[0];
  121. $illustration_id = get_post_meta($i->ID, '_chiefred_id', true);
  122. $illustration_alt = get_post_meta($i->ID, '_chiefred_alt', true);
  123. $illustration_title = get_post_meta($i->ID, '_chiefred_title', true);
  124. $attrs = ['class'=>$illustration_class, 'src'=>$src, 'alt'=>$illustration_alt, 'title'=>$illustration_title, 'width'=>$attachment_image[1], 'height'=>$attachment_image[2]];
  125. $link_attrs = ($illustration_link) ? ['class'=>$illustration_link_class, 'href'=>$href, 'rel'=>$illustration_link_rel, 'target'=>$illustration_link_target] : null;
  126. if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$article->content.'</div>')) {
  127. $dom = self::update_img($dom, 'chiefred_img_'.$illustration_id, $attrs, $link_attrs);
  128. $article->content = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper'));
  129. }
  130. }
  131. if ( get_option('chiefred_article_childrens') ) {
  132. $article->childrens = [];
  133. $cquery = new WP_Query( "post_type=page&post_status=publish&post_parent={$post->ID}&orderby=meta_value_num&order=ASC&meta_key=_chiefred_order&posts_per_page=-1" );
  134. foreach ($cquery->posts as $c) {
  135. $child = (object)[];
  136. $child->article_id = get_post_meta($c->ID, '_chiefred_id', true);
  137. $child->href = wp_get_canonical_url($c);
  138. $child->title = $c->post_title;
  139. $child->excerpt = $c->post_excerpt;
  140. $iquery = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_article_id&meta_value={$child->article_id}" );
  141. foreach ($iquery->posts as $i) {
  142. $attachment_image = wp_get_attachment_image_src($i->ID, $illustration_size);
  143. $src = $attachment_image[0];
  144. $href = wp_get_attachment_image_src($i->ID, 'full')[0];
  145. $illustration_id = get_post_meta($i->ID, '_chiefred_id', true);
  146. $illustration_alt = get_post_meta($i->ID, '_chiefred_alt', true);
  147. $illustration_title = get_post_meta($i->ID, '_chiefred_title', true);
  148. $attrs = ['class'=>$illustration_class, 'src'=>$src, 'alt'=>$illustration_alt, 'title'=>$illustration_title, 'width'=>$attachment_image[1], 'height'=>$attachment_image[2]];
  149. $link_attrs = ($illustration_link) ? ['class'=>$illustration_link_class, 'href'=>$href, 'rel'=>$illustration_link_rel, 'target'=>$illustration_link_target] : null;
  150. if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$child->excerpt.'</div>')) {
  151. $dom = self::update_img($dom, 'chiefred_img_'.$illustration_id, $attrs, $link_attrs);
  152. $child->excerpt = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper'));
  153. }
  154. }
  155. $article->childrens[] = $child;
  156. }
  157. }
  158. if ( get_option('chiefred_article_was_useful') ) {
  159. $article->was_useful = true;
  160. }
  161. return ChiefRed::view( 'article', compact('article'), true );
  162. } else {
  163. return $content;
  164. }
  165. }
  166. public static function was_useful(WP_REST_Request $request)
  167. {
  168. $ret = ["code"=>200, "message"=>"ok"];
  169. $post = $request->get_body_params();
  170. if (
  171. ! isset( $post['chiefred_token'] )
  172. || ! wp_verify_nonce( $post['chiefred_token'], 'wp_rest' )
  173. ) {
  174. exit('CSRF');
  175. } else {
  176. $api_port = get_option('chiefred_api_port');
  177. $sync_base = (CHIEFRED_LOCAL_DEBUG) ? CHIEFRED_LOCAL_BASE.":{$api_port}/sync/v1" : "https://chiefred.com:{$api_port}/sync/v1";
  178. $site_id = get_option('chiefred_site_id');
  179. $sync_secret = get_option('chiefred_api_secret');
  180. if (!$api_port || !$site_id || !$sync_secret) {
  181. return $ret;
  182. }
  183. $scrollpath = intval($post['scrollpath']);
  184. $objection = (object)[
  185. 'article_id' => intval($post['article_id']),
  186. 'is_error' => ('error' == $post['type']) ? 1 : 0,
  187. 'message' => sanitize_text_field($post['message']),
  188. ];
  189. if($scrollpath == 0) return $ret;
  190. if(time() - $_SESSION['starttime'] < 30) return $ret;
  191. if(mb_strlen($objection->message) < 10) return $ret;
  192. if(mb_strpos($objection->message, 'http://') !== false) return $ret;
  193. if(mb_strpos($objection->message, 'https://') !== false) return $ret;
  194. if(mb_strpos($objection->message, 'www.') !== false) return $ret;
  195. $data = json_encode($objection);
  196. $challenge = md5(uniqid());
  197. $sign = md5($challenge . $data . $sync_secret);
  198. $ch = curl_init();
  199. curl_setopt($ch, CURLOPT_URL, "{$sync_base}/objection/{$challenge}/{$site_id}/{$sign}");
  200. curl_setopt($ch, CURLOPT_POST, 1);
  201. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  202. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  203. if (CHIEFRED_LOCAL_DEBUG) {
  204. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  205. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  206. }
  207. $raw_resp = curl_exec($ch);
  208. curl_close ($ch);
  209. return $ret;
  210. }
  211. }
  212. public static function sync(WP_REST_Request $request)
  213. {
  214. $get = $request->get_query_params();
  215. $challenge = preg_replace('[^a-zA-Z0-9]', '', (isset($get['challenge']))?$get['challenge']: '');
  216. if ($challenge) {
  217. if ($_SERVER['REMOTE_ADDR'] == get_option('chiefred_api_ip')) {
  218. wp_schedule_single_event( time(), 'chiefred_synchronize' );
  219. return ["code"=>200, "message"=>"ok", "data"=>null, "sign"=>md5($challenge . get_option('chiefred_api_secret'))];
  220. } else {
  221. return ["code"=>401, "message"=>"Wrong Request IP", "data"=>null, "sign"=>null];
  222. }
  223. } else {
  224. return ["code"=>400, "message"=>"Wrong Request Format", "data"=>null, "sign"=>null];
  225. }
  226. }
  227. public static function canonical(WP_REST_Request $request)
  228. {
  229. $get = $request->get_query_params();
  230. $challenge = preg_replace('[^a-zA-Z0-9]', '', (isset($get['challenge']))?$get['challenge']: '');
  231. $article_id = intval((isset($_GET['article_id']))?$_GET['article_id']:0);
  232. if ($challenge && $article_id) {
  233. if ($_SERVER['REMOTE_ADDR'] == get_option('chiefred_api_ip')) {
  234. $query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article_id}&posts_per_page=1" );
  235. if ($query->have_posts()) {
  236. $query->the_post();
  237. $canonical = wp_get_canonical_url();
  238. wp_reset_postdata();
  239. $data = json_encode($canonical);
  240. return ["code"=>200, "message"=>"ok", "data"=>$data, "sign"=>md5($challenge . $data . get_option('chiefred_api_secret'))];
  241. } else {
  242. return ["code"=>404, "message"=>"Article Not Found", "data"=>null, "sign"=>null];
  243. }
  244. } else {
  245. return ["code"=>401, "message"=>"Wrong Request IP", "data"=>null, "sign"=>null];
  246. }
  247. } else {
  248. return ["code"=>400, "message"=>"Wrong Request Format", "data"=>null, "sign"=>null];
  249. }
  250. }
  251. public static function synchronize()
  252. {
  253. $sync_lock = intval(get_option('chiefred_sync_lock', 0));
  254. if ($sync_lock+600 > time()) {
  255. chiefred_log_i('Сеанс синхронизации перенесен на 5 минут в связи с блокировкой, установленной другим сенасом');
  256. wp_schedule_single_event( time()+300, 'chiefred_synchronize' );
  257. return;
  258. }
  259. update_option('chiefred_sync_lock', time());
  260. file_put_contents( CHIEFRED_PLUGIN_DIR . '/logs/chiefred.log', '' );
  261. $api_port = get_option('chiefred_api_port');
  262. $sync_base = (CHIEFRED_LOCAL_DEBUG) ? CHIEFRED_LOCAL_BASE.":{$api_port}/sync/v1" : "https://chiefred.com:{$api_port}/sync/v1";
  263. $site_id = get_option('chiefred_site_id');
  264. $sync_secret = get_option('chiefred_api_secret');
  265. $illustration_size = get_option('chiefred_illustration_size', 'medium');
  266. $illustration_class = get_option('chiefred_illustration_class');
  267. if (!$api_port || !$site_id || !$sync_secret) {
  268. chiefred_log_e('СИНХРОНИЗАЦИЯ НЕВОЗМОЖНА: Необходимо произвести настройку плагина для взаимодействия с Редакцией');
  269. return;
  270. }
  271. $dom = new DOMDocument('1.0', 'UTF-8');
  272. libxml_use_internal_errors(true);
  273. chiefred_log_i('Начало процесса синхронизации');
  274. $max_query = new WP_Query( array( 'post_type' => 'page', 'post_status' => 'publish', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_id','posts_per_page'=>1) );
  275. if ($max_query->have_posts()) {
  276. $max_query->the_post();
  277. $post_id = get_the_ID();
  278. $max_id = get_post_meta( $post_id, '_chiefred_id', true );
  279. wp_reset_postdata();
  280. } else {
  281. $max_id = 0;
  282. }
  283. $max_query = new WP_Query( array( 'post_type' => 'page', 'post_status' => 'publish', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_sync_at','posts_per_page'=>1) );
  284. if ($max_query->have_posts()) {
  285. $max_query->the_post();
  286. $post_id = get_the_ID();
  287. $sync_at = get_post_meta( $post_id, '_chiefred_sync_at', true );
  288. wp_reset_postdata();
  289. } else {
  290. $sync_at = 0;
  291. }
  292. chiefred_log_i("Запрашиваем обновления статей с параметрами: \$max_id={$max_id}, \$sync_at={$sync_at}");
  293. $challenge = md5(uniqid());
  294. $raw_resp = self::file_get_contents_curl("{$sync_base}/articles/{$challenge}/{$site_id}/{$max_id}/{$sync_at}");
  295. //chiefred_log_d("raw_resp", $raw_resp);
  296. $resp = json_decode($raw_resp);
  297. if($resp && $resp->code==200){
  298. chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)");
  299. $data = json_encode($resp->data);
  300. if (md5($challenge . $data . $sync_secret) == $resp->sign) {
  301. chiefred_log_i("Подпись данных верна");
  302. $articles_ids = $resp->data;
  303. $articles_update_count = 0;
  304. foreach ($articles_ids as $article_id) {
  305. $articles_update_count++;
  306. if ($articles_update_count > 2) {
  307. chiefred_log_i("Есть еще статьи, требующие обновления, но в текущем сеансе достигнута квота по статьям.");
  308. if (false !== wp_schedule_single_event( time()+300, 'chiefred_synchronize' )) {
  309. chiefred_log_i("Поэтому, ставим еще одно задание по синхронизации через 5 минут");
  310. }
  311. break;
  312. }
  313. chiefred_log_i("Нужно обновить статью с id={$article_id}");
  314. $challenge = md5(uniqid());
  315. $raw_resp = self::file_get_contents_curl("{$sync_base}/article/{$challenge}/{$site_id}/{$article_id}");
  316. $resp = json_decode($raw_resp);
  317. //chiefred_log_d("resp", $resp);
  318. if($resp && $resp->code==200){
  319. chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)");
  320. $data = json_encode($resp->data);
  321. if (md5($challenge . $data . $sync_secret) == $resp->sign) {
  322. chiefred_log_i("Подпись данных верна");
  323. $article = $resp->data;
  324. $article->creators = json_encode($article->creators);
  325. $query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article->id}" );
  326. if ($query->have_posts()) {
  327. chiefred_log_i("На сайте обнаружена статья с id={$article_id} - обновим ее");
  328. $query->the_post();
  329. $the_post = array();
  330. $the_post['ID'] = get_the_ID();
  331. $the_post['post_title'] = $article->title;
  332. $the_post['post_excerpt'] = str_replace('<img data-id', '<img id', $article->short);
  333. $the_post['post_content'] = str_replace('<img data-id', '<img id', $article->full);
  334. remove_action( 'post_updated', 'wp_save_post_revision' );
  335. if (wp_update_post( $the_post )) {
  336. chiefred_log_i("Статья успешно обновлена");
  337. }
  338. add_action( 'post_updated', 'wp_save_post_revision' );
  339. chiefred_log_d("the_post", $the_post);
  340. update_post_meta($the_post['ID'], '_chiefred_parent_id', $article->parent_id);
  341. update_post_meta($the_post['ID'], '_chiefred_order', $article->order);
  342. update_post_meta($the_post['ID'], '_chiefred_keyword', $article->keyword);
  343. update_post_meta($the_post['ID'], '_chiefred_description', $article->description);
  344. update_post_meta($the_post['ID'], '_chiefred_creators', $article->creators);
  345. update_post_meta($the_post['ID'], '_chiefred_sync_at', $article->sync_at);
  346. chiefred_log_d("the_post_metas", get_post_meta($the_post['ID']));
  347. wp_reset_postdata();
  348. } else {
  349. chiefred_log_i("На сайте нет статьи с id={$article_id} - добавляем");
  350. $the_post = array();
  351. if ($article->parent_id>0) {
  352. chiefred_log_i("Полученная статья является дочерней \$parent_id={$article->parent_id} - ищем родительскую на сайте");
  353. $query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$article->parent_id}" );
  354. if ($query->have_posts()) {
  355. $query->the_post();
  356. $the_post['post_parent'] = get_the_ID();
  357. $the_post['menu_order'] = $article->order;
  358. wp_reset_postdata();
  359. chiefred_log_i("Родительская статья обнаружена - устанавливаем связь");
  360. }
  361. }
  362. $the_post['post_author'] = 1;
  363. $the_post['post_type'] = 'page';
  364. $the_post['post_status'] = 'publish';
  365. $the_post['post_title'] = $article->title;
  366. $the_post['post_excerpt'] = str_replace('<img data-id="', '<img id="chiefred_img_', $article->short);
  367. $the_post['post_content'] = str_replace('<img data-id="', '<img id="chiefred_img_', $article->full);
  368. $the_post['post_name'] = $article->keyword;
  369. chiefred_log_d("the_post", $the_post);
  370. $post_id = wp_insert_post($the_post, false);
  371. if ($post_id) {
  372. chiefred_log_i("Статья успешно добавлена");
  373. }
  374. add_post_meta($post_id, '_chiefred_id', $article->id, true);
  375. add_post_meta($post_id, '_chiefred_parent_id', $article->parent_id, true);
  376. add_post_meta($post_id, '_chiefred_order', $article->order, true);
  377. add_post_meta($post_id, '_chiefred_keyword', $article->keyword, true);
  378. add_post_meta($post_id, '_chiefred_description', $article->description, true);
  379. add_post_meta($post_id, '_chiefred_creators', wp_slash($article->creators), true);
  380. add_post_meta($post_id, '_chiefred_sync_at', $article->sync_at, true);
  381. chiefred_log_d("the_post_metas", get_post_meta($post_id));
  382. wp_reset_postdata();
  383. }
  384. } else {
  385. chiefred_log_w("Проверка подписи провалена");
  386. }
  387. } else {
  388. if (!$resp) {
  389. chiefred_log_w("Сервер {$sync_base} не ответил на запрос");
  390. } else {
  391. chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}");
  392. }
  393. }
  394. }
  395. } else {
  396. chiefred_log_w("Проверка подписи провалена");
  397. }
  398. } else {
  399. if (!$resp) {
  400. chiefred_log_w("Сервер {$sync_base} не ответил на запрос");
  401. } else {
  402. chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}");
  403. }
  404. }
  405. ///// Иллюстрации /////
  406. $max_query = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image/jpeg', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_id','posts_per_page'=>1) );
  407. if ($max_query->have_posts()) {
  408. $max_query->the_post();
  409. $post_id = get_the_ID();
  410. $max_id = get_post_meta( $post_id, '_chiefred_id', true );
  411. wp_reset_postdata();
  412. } else {
  413. $max_id = 0;
  414. }
  415. $max_query = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image/jpeg', 'orderby'=>'meta_value_num', 'order'=>'DESC','meta_key'=>'_chiefred_sync_at','posts_per_page'=>1) );
  416. if ($max_query->have_posts()) {
  417. $max_query->the_post();
  418. $post_id = get_the_ID();
  419. $sync_at = get_post_meta( $post_id, '_chiefred_sync_at', true );
  420. wp_reset_postdata();
  421. } else {
  422. $sync_at = 0;
  423. }
  424. chiefred_log_i("Запрашиваем обновления иллюстраций с параметрами: \$max_id={$max_id}, \$sync_at={$sync_at}");
  425. $challenge = md5(uniqid());
  426. $raw_resp = self::file_get_contents_curl("{$sync_base}/illustrations/{$challenge}/{$site_id}/{$max_id}/{$sync_at}");
  427. $resp = json_decode($raw_resp);
  428. //chiefred_log_d("resp", $resp);
  429. if($resp && $resp->code==200){
  430. chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)");
  431. $data = json_encode($resp->data);
  432. if (md5($challenge . $data . $sync_secret) == $resp->sign) {
  433. chiefred_log_i("Подпись данных верна");
  434. $illustrations_ids = $resp->data;
  435. $illustrations_update_count = 0;
  436. foreach ($illustrations_ids as $illustration_id) {
  437. $illustrations_update_count++;
  438. if ($illustrations_update_count > 16) {
  439. chiefred_log_i("Есть еще иллюстрации, требующие обновления, но в текущем сеансе достигнута квота по иллюстрациям.");
  440. if (false !== wp_schedule_single_event( time()+300, 'chiefred_synchronize' )) {
  441. chiefred_log_i("Поэтому, ставим еще одно задание по синхронизации через 5 минут");
  442. }
  443. break;
  444. }
  445. chiefred_log_i("Нужно обновить иллюстрацию с id={$illustration_id}");
  446. $challenge = md5(uniqid());
  447. $raw_resp = self::file_get_contents_curl("{$sync_base}/illustration/{$challenge}/{$site_id}/{$illustration_id}");
  448. $resp = json_decode($raw_resp);
  449. //chiefred_log_d("resp", $resp);
  450. if($resp && $resp->code==200){
  451. chiefred_log_i("Получен ответ Редакции с кодом 200 (ок)");
  452. $data = json_encode($resp->data);
  453. if (md5($challenge . $data . $sync_secret) == $resp->sign) {
  454. chiefred_log_i("Подпись данных верна");
  455. $illustration = $resp->data;
  456. $query = new WP_Query( "post_type=attachment&post_status=inherit&post_mime_type=image/jpeg&meta_key=_chiefred_id&meta_value={$illustration->id}" );
  457. if ($query->have_posts()) {
  458. chiefred_log_i("На сайте обнаружена иллюстрация с id={$article_id} - заменяем ее");
  459. $query->the_post();
  460. $attachment_id = get_the_ID();
  461. wp_reset_postdata();
  462. wp_delete_attachment( $attachment_id, true );
  463. }
  464. $query = new WP_Query( "post_type=page&post_status=publish&meta_key=_chiefred_id&meta_value={$illustration->article_id}" );
  465. if ($query->have_posts()) {
  466. $query->the_post();
  467. $the_post = get_post(get_the_ID(), OBJECT);
  468. wp_reset_postdata();
  469. chiefred_log_i("На сайте найдена статья, к которой относится иллюстрация");
  470. $upload_dir = wp_upload_dir();
  471. $upload_path = str_replace( '/', DIRECTORY_SEPARATOR, $upload_dir['path'] ) . DIRECTORY_SEPARATOR;
  472. $img = $illustration->image;
  473. $img = str_replace('data:image/jpeg;base64,', '', $img);
  474. $img = str_replace(' ', '+', $img);
  475. $img_decoded = base64_decode($img);
  476. $filename = $illustration->id . '.jpeg';
  477. $hashed_filename = md5( $filename . microtime() ) . '_' . $filename;
  478. $image_upload = file_put_contents( $upload_path . $hashed_filename, $img_decoded );
  479. if( !function_exists( 'wp_handle_sideload' ) ) {
  480. require_once( ABSPATH . 'wp-admin/includes/file.php' );
  481. }
  482. if( !function_exists( 'wp_get_current_user' ) ) {
  483. require_once( ABSPATH . 'wp-includes/pluggable.php' );
  484. }
  485. $file = array();
  486. $file['error'] = '';
  487. $file['tmp_name'] = $upload_path . $hashed_filename;
  488. $file['name'] = $hashed_filename;
  489. $file['type'] = 'image/jpeg';
  490. $file['size'] = filesize( $upload_path . $hashed_filename );
  491. $file_return = wp_handle_sideload( $file, array( 'test_form' => false ) );
  492. $filename = $file_return['file'];
  493. $attachment = array(
  494. 'post_author' => 1,
  495. 'post_mime_type' => $file_return['type'],
  496. 'post_title' => $illustration->name,
  497. 'post_content' => $illustration->title,
  498. 'post_status' => 'inherit',
  499. 'guid' => $upload_dir['url'] . '/' . basename($filename)
  500. );
  501. chiefred_log_i("Иллюстрация сохранена в файл: {$attachment['guid']}");
  502. $attach_id = wp_insert_attachment( $attachment, $filename, $the_post->ID );
  503. require_once(ABSPATH . 'wp-admin/includes/image.php');
  504. $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
  505. wp_update_attachment_metadata( $attach_id, $attach_data );
  506. add_post_meta($attach_id, '_chiefred_id', $illustration->id, true);
  507. add_post_meta($attach_id, '_chiefred_article_id', $illustration->article_id, true);
  508. add_post_meta($attach_id, '_chiefred_sync_at', $illustration->sync_at, true);
  509. add_post_meta($attach_id, '_chiefred_alt', $illustration->name, true);
  510. add_post_meta($attach_id, '_chiefred_title', $illustration->title, true);
  511. chiefred_log_d("\$attach_id={$attach_id}");
  512. $t = $illustration;
  513. $t->image = '<truncated>';
  514. chiefred_log_d("\$illustration", $illustration);
  515. $image = imagecreatefromstring($img_decoded);
  516. @$iSize = getimagesizefromstring($img_decoded);
  517. if ($image && $iSize) {
  518. foreach ($attach_data['sizes'] as $size_name => $size) {
  519. if (CHIEFRED_SMALL_IMG_WIDTH_LIMIT > $size['width']) {
  520. $k = max($size['width'] / 120, $size['height'] / 90);
  521. $newwidth = $iSize[0] * $illustration->preview_s_z * $k;
  522. $newheight = $iSize[1] * $illustration->preview_s_z * $k;
  523. $resized = imagecreatetruecolor($newwidth, $newheight);
  524. $dest = imagecreatetruecolor($size['width'], $size['height']);
  525. imagecopyresampled($resized, $image, 0, 0, 0, 0, $newwidth, $newheight, $iSize[0], $iSize[1]);
  526. imagecopy($dest, $resized, 0, 0, -1*$illustration->preview_s_x*$k, -1*$illustration->preview_s_y*$k, $size['width'], $size['height']);
  527. imagedestroy($resized);
  528. ob_start();
  529. imagejpeg($dest, "{$upload_dir['path']}/{$size['file']}");
  530. ob_end_clean();
  531. imagedestroy($dest);
  532. } elseif(CHIEFRED_MEDIUM_IMG_WIDTH_LIMIT > $size['width']) {
  533. $k = max($size['width'] / 240, $size['height'] / 180);
  534. $newwidth = $iSize[0] * $illustration->preview_m_z * $k;
  535. $newheight = $iSize[1] * $illustration->preview_m_z * $k;
  536. $resized = imagecreatetruecolor($newwidth, $newheight);
  537. $dest = imagecreatetruecolor($size['width'], $size['height']);
  538. imagecopyresampled($resized, $image, 0, 0, 0, 0, $newwidth, $newheight, $iSize[0], $iSize[1]);
  539. imagecopy($dest, $resized, 0, 0, -1*$illustration->preview_m_x*$k, -1*$illustration->preview_m_y*$k, $size['width'], $size['height']);
  540. imagedestroy($resized);
  541. ob_start();
  542. imagejpeg($dest, "{$upload_dir['path']}/{$size['file']}");
  543. ob_end_clean();
  544. imagedestroy($dest);
  545. }
  546. }
  547. imagedestroy($image);
  548. $iSize = null;
  549. }
  550. $src = wp_get_attachment_image_src($attach_id, $illustration_size)[0];
  551. chiefred_log_d("img \$illustration_class:{$illustration_class} \$illustration_size:{$illustration_size} \$src:{$src}");
  552. $attrs = ['class'=>$illustration_class, 'src'=>$src];
  553. if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$the_post->post_excerpt.'</div>')) {
  554. $dom = self::update_img($dom, 'chiefred_img_'.$illustration->id, $attrs);
  555. $the_post->post_excerpt = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper'));
  556. }
  557. if (false !== $dom->loadHTML('<?xml encoding="UTF-8"><div id="chiefred-wrapper">'.$the_post->post_content.'</div>')) {
  558. $dom = self::update_img($dom, 'chiefred_img_'.$illustration->id, $attrs);
  559. $the_post->post_content = self::DOMinnerHTML($dom->getElementById('chiefred-wrapper'));
  560. }
  561. remove_action( 'post_updated', 'wp_save_post_revision' );
  562. if (wp_update_post( $the_post )) {
  563. chiefred_log_i("Страница иллюстрации успешно обновлена");
  564. } else {
  565. chiefred_log_w("Страницу иллюстрации обновить НЕ УДАЛОСЬ");
  566. }
  567. add_action( 'post_updated', 'wp_save_post_revision' );
  568. } else {
  569. chiefred_log_i("Иллюстрации без привязки к статье нам не нужны - загрузим потом");
  570. continue;
  571. }
  572. } else {
  573. chiefred_log_w("Проверка подписи провалена");
  574. }
  575. } else {
  576. if (!$resp) {
  577. chiefred_log_w("Сервер {$sync_base} не ответил на запрос");
  578. } else {
  579. chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}");
  580. }
  581. }
  582. }
  583. } else {
  584. chiefred_log_w("Проверка подписи провалена");
  585. }
  586. } else {
  587. if (!$resp) {
  588. chiefred_log_w("Сервер {$sync_base} не ответил на запрос");
  589. } else {
  590. chiefred_log_w("Сервер вернул ошибку - code:{$resp->code}, message:{$resp->message}");
  591. }
  592. }
  593. chiefred_log_i('Процесс синхронизации завершен');
  594. update_option('chiefred_sync_lock', 0);
  595. }
  596. // [ UTILS ] /////////////////////////////////////////////////////////////////////////////////////////////////////
  597. public static function update_img(DOMDocument $dom, $id=null, $attrs=[], $link_attrs=null)
  598. {
  599. foreach ($dom->getElementsByTagName('img') as $item) {
  600. if ($item->getAttribute('id') == $id) {
  601. foreach ($attrs as $attr => $val) {
  602. if ($val) {
  603. $item->setAttribute($attr, $val);
  604. } else {
  605. $item->removeAttribute($attr);
  606. }
  607. }
  608. if (null !== $link_attrs && 'a' != $item->parentNode->tagName) {
  609. $link = $dom->createElement('a');
  610. foreach ($link_attrs as $attr => $val) {
  611. if ($val) {
  612. $link->setAttribute($attr, $val);
  613. } else {
  614. $link->removeAttribute($attr);
  615. }
  616. }
  617. $item->parentNode->replaceChild($link, $item);
  618. $link->appendChild($item);
  619. }
  620. }
  621. }
  622. return $dom;
  623. }
  624. public static function get_image_sizes( $size = '' )
  625. {
  626. global $_wp_additional_image_sizes;
  627. $sizes = array();
  628. $get_intermediate_image_sizes = get_intermediate_image_sizes();
  629. foreach( $get_intermediate_image_sizes as $_size ) {
  630. if ( in_array( $_size, array( 'thumbnail', 'medium', 'medium_large', 'large' ) ) ) {
  631. $sizes[ $_size ]['width'] = get_option( $_size . '_size_w' );
  632. $sizes[ $_size ]['height'] = get_option( $_size . '_size_h' );
  633. $sizes[ $_size ]['crop'] = (bool) get_option( $_size . '_crop' );
  634. } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
  635. $sizes[ $_size ] = array(
  636. 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
  637. 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
  638. 'crop' => $_wp_additional_image_sizes[ $_size ]['crop']
  639. );
  640. }
  641. }
  642. if ( $size ) {
  643. if( isset( $sizes[ $size ] ) ) {
  644. return $sizes[ $size ];
  645. } else {
  646. return false;
  647. }
  648. }
  649. return $sizes;
  650. }
  651. public static function DOMinnerHTML(DOMNode $element)
  652. {
  653. $innerHTML = "";
  654. $children = $element->childNodes;
  655. foreach ($children as $child)
  656. {
  657. $innerHTML .= $element->ownerDocument->saveHTML($child);
  658. }
  659. return $innerHTML;
  660. }
  661. public static function view( $name, array $args = array(), $as_string=false )
  662. {
  663. foreach ( $args AS $key => $val ) {
  664. $$key = $val;
  665. }
  666. if (file_exists(CHIEFRED_PLUGIN_DIR."views/{$name}.php")) {
  667. $file = CHIEFRED_PLUGIN_DIR."views/{$name}.php";
  668. } elseif(file_exists(CHIEFRED_PLUGIN_DIR."views/{$name}.default.php")) {
  669. $file = CHIEFRED_PLUGIN_DIR."views/{$name}.default.php";
  670. } else {
  671. return 'ChiefRedERROR: View ($name) not found';
  672. }
  673. if($as_string) {
  674. ob_start();
  675. }
  676. include( $file );
  677. if($as_string) {
  678. return ob_get_clean();
  679. }
  680. }
  681. public static function file_get_contents_curl($url)
  682. {
  683. $ch = curl_init();
  684. curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
  685. curl_setopt($ch, CURLOPT_HEADER, 0);
  686. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  687. curl_setopt($ch, CURLOPT_URL, $url);
  688. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
  689. if (CHIEFRED_LOCAL_DEBUG) {
  690. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
  691. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
  692. }
  693. $data = curl_exec($ch);
  694. curl_close($ch);
  695. return $data;
  696. }
  697. }