PluginProbe
codoc / 0.9.57
codoc v0.9.57
0.9.8.8 0.9.8.9 0.9.9 0.9.9.1 trunk 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.8.1 0.8.2 0.8.3 0.8.4 0.8.6 0.8.7 0.8.8 0.8.9 0.9 0.9.1 0.9.10 0.9.11 All 114 releases
codoc / class-codoc-util.php

class-codoc-util.php in codoc 0.9.57, at class-codoc-util.php

524 lines 21.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WPINC')) {
4 define( 'WPINC', 'wp-includes' );
5 }
6
7 if (!defined('CODOC_URL')) {
8 define( 'CODOC_URL', 'https://codoc.jp' );
9 }
10 global $wp_version;
11 if (version_compare( $wp_version,'5.9') >= 0 ) {
12 require_once( ABSPATH . WPINC . '/class-wp-http.php');
13 } else {
14 require_once( ABSPATH . WPINC . '/class-http.php');
15 }
16
17 require_once( ABSPATH . WPINC . '/class-wp-error.php');
18
19 final class CodocUtil {
20 public $codoc_url = CODOC_URL;
21 public function __construct($params = ['usercode' => null, 'token' => null,'codoc_url' => null]) {
22 $this->setAuthInfo(['usercode' => $params['usercode'], 'token' => $params['token']]);
23 if (isset($params['codoc_url'])) {
24 $this->codoc_url = $params['codoc_url'];
25 }
26 return $this;
27 }
28
29 public function callAPI($method,$path,$body = [],$headers = []) {
30 $usercode = $this->usercode;
31 $token = $this->token;
32
33 $headers['X-CodocToken'] = $token;
34 $host = $this->codoc_url;
35 $sslverify = true;
36
37 if (preg_match('/local/',$this->codoc_url)) {
38 $sslverify = false;
39 $host = 'https://host.docker.internal';
40 }
41 $url = sprintf("%s/api/v1/cms/%s%s",$host,$usercode,$path);
42 $http = new WP_Http();
43 try {
44 $response = $http->request(
45 $url,
46 [
47 'sslverify' => $sslverify,
48 'method' => $method,
49 'timeout' => 10,
50 'headers' => $headers,
51 'body' => $body,
52 ]
53 );
54 // notification を処理
55 $body = json_decode($response['body'],true);
56 if (isset($body['notification']) && !empty($body['notification'])) {
57 // notification をトランジェントに保存(24時間保持)
58 set_transient('codoc_api_notification', $body['notification'], DAY_IN_SECONDS);
59 }
60 if ( is_wp_error($response) || $response['response']['code'] != 200 ) {
61 //何もしない
62 //var_dump( $response );
63 }
64 } catch(Exception $e) {
65
66 }
67 if (!is_wp_error($response) and
68 isset($response['body']) and
69 is_string($response['body']) and
70 is_array(json_decode($response['body'], true)) and
71 (json_last_error() == JSON_ERROR_NONE)) {
72 return json_decode($response['body']);
73 } else {
74 return null;
75 }
76 }
77 public function callPaywallAPI($method,$path,$body = [],$headers = []) {
78 $site_usercode = get_option(CODOC_USERCODE_OPTION_NAME);
79 $paywall_token = $this->get_paywall_token_code();
80
81 $host = $this->codoc_url;
82 $sslverify = true;
83
84 if (preg_match('/local/',$this->codoc_url)) {
85 $sslverify = false;
86 $host = 'https://host.docker.internal';
87 }
88 $url = sprintf("%s/api/v1/paywall/%s%s",$host,$site_usercode,$path);
89 $http = new WP_Http();
90 try {
91 $response = $http->request(
92 $url,
93 [
94 'sslverify' => $sslverify,
95 'method' => $method,
96 'timeout' => 10,
97 'headers' => $headers,
98 'body' => $body,
99 ]
100 );
101 if ( is_wp_error($response) || $response['response']['code'] != 200 ) {
102 //何もしない
103 //var_dump( $response );
104 }
105 } catch(Exception $e) {
106
107 }
108 if (!is_wp_error($response) and
109 isset($response['body']) and
110 is_string($response['body']) and
111 is_array(json_decode($response['body'], true)) and
112 (json_last_error() == JSON_ERROR_NONE)) {
113 return json_decode($response['body']);
114 } else {
115 return null;
116 }
117 }
118 public function setAuthInfo($params = [ "usercode" => null, "token" => null ]) {
119 if ($params["usercode"]) {
120 $this->usercode = $params["usercode"];
121 }
122 if ($params["token"]) {
123 $this->token = $params["token"];
124 }
125 return true;
126 }
127 public function get_token($params = ["fetch_token_key" => null],$auth_info = ["usercode" => null, "token" => null]) {
128 $this->setAuthInfo($auth_info);
129 return $this->callAPI('GET','/token',[ "fetch_token_key" => $params["fetch_token_key"] ]);
130 }
131 public function get_user_info($params = [] ,$auth_info = ["usercode" => null, "token" => null]) {
132 $this->setAuthInfo($auth_info);
133 return $this->callAPI('GET','');
134 }
135 public function get_support_entry($params = [] ,$auth_info = ["usercode" => null, "token" => null]) {
136 $this->setAuthInfo($auth_info);
137 return $this->callAPI('GET','/support_entry');
138 }
139 public function sync_entry($params = [
140 "post_title" => null,
141 "post_content" => null,
142 "post_status" => null, # 0, 1
143 "post_permalink" => null,
144 "codoc_entry_code" => null,
145 ],$auth_info = ["usercode" => null, "token" => null]) {
146
147 $this->setAuthInfo($auth_info);
148
149 $post_content = $params['post_content'];
150 preg_match('/wp:codoc\/codoc-block +?({.*})/',$post_content,$matches);
151 // GUTENBERG で指定されたjson(記事�
152 )がない場合
153 if (!$matches) {
154 return;
155 }
156 // GUTENBERG で保存している�
157 容を取得
158 $codoc_info = json_decode($matches[1],true);
159 // codoc タグがない場合はなにもしない
160 //preg_match('/(<span +data-id="codoc-tag"[^>]+>(?:.+|)<\/span>)/',$post_content,$matches);
161 preg_match('/(<(?:span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:span|div)>)/',$post_content,$matches);
162 if (!$matches) {
163 return;
164 }
165 // TODO: split or html parse? HTMLがつながってる場合はおかしくなる
166 // classic(tinymce)版の場合p、もしくはdivにかこまれている
167 $end_tag_regex = '/<(?:div|p)>::CODOC_WP_END_PAYWALL::<\/(?:div|p)>/';
168 $before_splited = preg_split($end_tag_regex,$post_content);
169 $post_content = $before_splited[0];
170 $splited = preg_split('/(?:<(?:div|p)(?:[^>]+|)>|)<\!-- +wp:codoc\/codoc-block .*<\!-- +\/wp:codoc\/codoc-block +-->(?:<\/(?:div|p)>|)/s',$post_content);
171 $status = $params['post_status']; # 0: 非�
172 �開 1: �
173 �開 2:限定�
174 �開(パスワードの場合は限定�
175 �開で同期する)
176 // codoc設定で限定�
177 �開を有効で、�
178 �開の場合は 限定�
179 �開にする
180 if ($status == 1 and isset($codoc_info['statusLimited']) and $codoc_info['statusLimited']) {
181 $status = 2;
182 }
183 # $body_free = '';
184 # $body_paywalled = '';
185 # if (count($splited) >= 2) {
186 #
187 # }
188 $binded_url = $params['post_permalink'];
189 $CODOC_SETTINGS = get_option(CODOC_SETTINGS_OPTION_NAME);
190 if (isset($CODOC_SETTINGS['str_replace_binded_url_from']) and
191 isset($CODOC_SETTINGS['str_replace_binded_url_to']) and
192 $CODOC_SETTINGS['str_replace_binded_url_from']) {
193 $binded_url = str_replace(sanitize_text_field($CODOC_SETTINGS['str_replace_binded_url_from']),
194 sanitize_text_field($CODOC_SETTINGS['str_replace_binded_url_to']),
195 $binded_url);
196 }
197 $api_params = [
198 'title' => $params['post_title'],
199 'body_free' => $splited[0],
200 'body_paywalled' => $splited[1],
201 'status' => $status,
202 'binded_url' => $binded_url,
203 'show_price' => isset($codoc_info['showPrice']) ? ($codoc_info['showPrice'] ? 1 : 0) : 0,
204 'price' => isset($codoc_info['price']) ? $codoc_info['price'] : 100,
205 'limited' => isset($codoc_info['limited']) ? ($codoc_info['limited'] ? 1 : 0) : 0,
206 'limited_count' => isset($codoc_info['limitedCount']) ? $codoc_info['limitedCount'] : 1,
207 'affiliate_mode' => isset($codoc_info['affiliateMode']) ? ($codoc_info['affiliateMode'] ? 1 : 0) : 0,
208 'affiliate_rate' => isset($codoc_info['affiliateRate']) ? $codoc_info['affiliateRate'] : '0.0500',
209 'show_support' => isset($codoc_info['showSupport']) ? ($codoc_info['showSupport'] ? 1 : 0) : 0,
210 'show_paywalled_support' => isset($codoc_info['showPaywalledSupport']) ? ($codoc_info['showPaywalledSupport'] ? 1 : 0) : 0,
211 'subscriptions' => isset($codoc_info['subscriptions']) ? array_keys($codoc_info['subscriptions']) : [],
212 ];
213 $entryCode = $params['codoc_entry_code'];
214 $res = null;
215 if ($entryCode) {
216 $res = $this->callAPI('PUT','/entries/' . $entryCode ,$api_params);
217 } else {
218 $res = $this->callAPI('POST', '/entries', $api_params);
219 }
220 return $res;
221 }
222
223 function post_thumbnail( $params = [
224 "file_path" => null,
225 "boundary" => null,
226 "codoc_entry_code" => null,
227 ], $auth_info = ["usercode" => null, "token" => null] ) {
228
229 $this->setAuthInfo($auth_info);
230
231 $file_path = $params['file_path'];
232 $boundary = $params['boundary']; # ランダム変数24桁 wp_generate_password(24);
233 $res = null;
234 if (is_readable($file_path)) {
235 $name = 'file';
236
237 $payload = '';
238 $payload .= '--' . $boundary;
239 $payload .= "\r\n";
240 $payload .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . basename( $file_path ) . '"' . "\r\n";
241 $payload .= "Content-Type: application/octet-stream\r\n";
242 $payload .= "Content-Transfer-Encoding: binary\r\n";
243 $payload .= "\r\n";
244 $payload .= file_get_contents( $file_path );
245 $payload .= "\r\n";
246
247 $payload .= '--' . $boundary . '--';
248
249 $entryCode = $params['codoc_entry_code'];
250 $res = $this->callAPI(
251 'POST',
252 '/entries/' . $entryCode . '/thumbnail',
253 $payload,
254 ['content-type' => 'multipart/form-data; boundary=' . $boundary]
255 );
256 }
257 return $res;
258 }
259
260 function reset_thumbnail( $params = [
261 "codoc_entry_code" => null,
262 ],$auth_info = ["usercode" => null, "token" => null] ) {
263
264 $this->setAuthInfo($auth_info);
265
266 $entryCode = $params['codoc_entry_code'];
267 $res = $this->callAPI(
268 'POST',
269 '/entries/' . $entryCode . '/thumbnail',
270 [ "reset" => 1 ]
271 );
272 return $res;
273 }
274
275 function filter_content( $params = [
276 "post_content" => null,
277 "preview" => null,
278 "codoc_entry_code" => null,
279 "codoc_settings" => null,
280 "is_amp_endpoint" => null,
281 "post_permalink" => null,
282 "codoc_support_entry_code" => null,
283 ]) {
284 $CODOC_SETTINGS = $params['codoc_settings'];
285
286 $has_codoc_tag = '/(<(span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:div|span)>)/';
287 $post_content = $params['post_content'];
288 // codoc タグがあるかどうか (202001:span -> div に変更)
289 preg_match($has_codoc_tag,$post_content,$matches);
290
291 $show_support_message = '';
292 if (isset($CODOC_SETTINGS['show_support_message'])) {
293 $show_support_message = $CODOC_SETTINGS['show_support_message'];
294 }
295 $show_support_categories = '';
296 if (isset($CODOC_SETTINGS['show_support_categories'])) {
297 $show_support_categories = $CODOC_SETTINGS['show_support_categories'];
298 }
299 $show_support_location = 'bottom';
300 if (isset($CODOC_SETTINGS['show_support_location'])) {
301 $show_support_location = $CODOC_SETTINGS['show_support_location'];
302 }
303 // デフォルト値をうめておく
304 if (!isset($CODOC_SETTINGS['support_button_text'])) {
305 $CODOC_SETTINGS['support_button_text'] = 'サポートする';
306 }
307 if (!isset($CODOC_SETTINGS['show_like'])) {
308 $CODOC_SETTINGS['show_like'] = 1;
309 }
310 if (!isset($CODOC_SETTINGS['show_about_codoc'])) {
311 $CODOC_SETTINGS['show_about_codoc'] = 1;
312 }
313 if (!isset($CODOC_SETTINGS['show_powered_by'])) {
314 $CODOC_SETTINGS['show_powered_by'] = 1;
315 }
316 if (!isset($CODOC_SETTINGS['show_created_by'])) {
317 $CODOC_SETTINGS['show_created_by'] = 1;
318 }
319 if (!isset($CODOC_SETTINGS['show_copyright'])) {
320 $CODOC_SETTINGS['show_copyright'] = 1;
321 }
322 $show_support_entry = (is_single() && preg_grep("/(?:$show_support_categories)/",array_map( function($c) { return $c->name; },get_the_category(get_post()->ID))));
323 if (!$matches && ($support_entry_code = $params['codoc_support_entry_code']) && $show_support_entry) {
324 $support_tag = sprintf(
325 '<div class="codoc-entries" data-without-body="1" data-support-message="%s" id="codoc-entry-%s" data-support-button-text="%s" data-show-like="%s" data-show-about-codoc="%s" data-show-powered-by="%s" data-show-created-by="%s" data-show-copyright="%s"></div>',
326 htmlspecialchars($show_support_message,ENT_QUOTES),
327 $support_entry_code,
328 $CODOC_SETTINGS['support_button_text'],
329 $CODOC_SETTINGS['show_like'],
330 $CODOC_SETTINGS['show_about_codoc'],
331 $CODOC_SETTINGS['show_powered_by'],
332 $CODOC_SETTINGS['show_created_by'],
333 $CODOC_SETTINGS['show_copyright']
334 );
335 $post_content = $show_support_location == 'bottom' ?
336 $post_content . $support_tag :
337 $support_tag . $post_content ;
338 }
339
340 // data-wp-plugin-ver が無いタグは分割しない
341 if (!$matches) {
342 return $post_content;
343 }
344
345 // codocタグで分割 (202001: gutenbergで直前のdivタグを削除)
346 $tag_regex = '/(?:<div(?:[^>]+|)>|)<(?:span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:span|div)>(?:<\/div>|)/';
347 $end_tag_regex = '/<(?:div|p)>::CODOC_WP_END_PAYWALL::<\/(?:div|p)>/';
348 if ( $params['preview'] ) {
349 $post_content = preg_replace($tag_regex,'<div class="codoc-continue">ここから上は無料で表示されます</div>',$post_content);
350 $post_content = preg_replace($end_tag_regex,'<div class="codoc-continue">ここから下は無料で表示されます</div>',$post_content);
351 return $post_content;
352 }
353 // codoc タグの前後で分ける
354 $before_splited = preg_split($end_tag_regex,$post_content);
355 $splited = preg_split($tag_regex,$before_splited[0]);
356 // codoc タグにID属性のentrycodeとdata-without-body(無料分を非表示)をつける
357 $entryCodeFormated = sprintf('"codoc-entry-%s" ',$params['codoc_entry_code']);
358
359 // 文言系の設定をつける
360 $tagAttributes = '';
361 if (isset($CODOC_SETTINGS['show_like']) and $CODOC_SETTINGS['show_like'] != 1) {
362 $tagAttributes = $tagAttributes . sprintf(' data-show-like="%s"',$CODOC_SETTINGS['show_like']);
363 }
364 if (isset($CODOC_SETTINGS['show_about_codoc']) and $CODOC_SETTINGS['show_about_codoc'] != 1) {
365 $tagAttributes = $tagAttributes . sprintf(' data-show-about-codoc="%s"',$CODOC_SETTINGS['show_about_codoc']);
366 }
367 if (isset($CODOC_SETTINGS['show_powered_by']) and $CODOC_SETTINGS['show_powered_by'] != 1) {
368 $tagAttributes = $tagAttributes . sprintf(' data-show-powered-by="%s"',$CODOC_SETTINGS['show_powered_by']);
369 }
370 if (isset($CODOC_SETTINGS['show_created_by']) and $CODOC_SETTINGS['show_created_by'] != 1) {
371 $tagAttributes = $tagAttributes . sprintf(' data-show-created-by="%s"',$CODOC_SETTINGS['show_created_by']);
372 }
373 if (isset($CODOC_SETTINGS['show_copyright']) and $CODOC_SETTINGS['show_copyright'] != 1) {
374 $tagAttributes = $tagAttributes . sprintf(' data-show-copyright="%s"',$CODOC_SETTINGS['show_copyright']);
375 }
376 if (isset($CODOC_SETTINGS['entry_button_text']) and $CODOC_SETTINGS['entry_button_text'] != '') {
377 $tagAttributes = $tagAttributes . sprintf(' data-entry-button-text="%s"',$CODOC_SETTINGS['entry_button_text']);
378 }
379 if (isset($CODOC_SETTINGS['subscription_button_text']) and $CODOC_SETTINGS['subscription_button_text'] != '') {
380 $tagAttributes = $tagAttributes . sprintf(' data-subscription-button-text="%s"',$CODOC_SETTINGS['subscription_button_text']);
381 }
382 if (isset($CODOC_SETTINGS['support_button_text']) and $CODOC_SETTINGS['support_button_text'] != '') {
383 $tagAttributes = $tagAttributes . sprintf(' data-support-button-text="%s"',$CODOC_SETTINGS['support_button_text']);
384 }
385 if (isset($CODOC_SETTINGS['subscription_message']) and $CODOC_SETTINGS['subscription_message'] != '') {
386 $tagAttributes = $tagAttributes . sprintf(' data-subscription-message="%s"',$CODOC_SETTINGS['subscription_message']);
387 }
388 if (isset($CODOC_SETTINGS['support_message']) and $CODOC_SETTINGS['support_message'] != '') {
389 $tagAttributes = $tagAttributes . sprintf(' data-support-message="%s"',$CODOC_SETTINGS['support_message']);
390 }
391 if (isset($CODOC_SETTINGS['codoc_tag_attributes']) and $CODOC_SETTINGS['codoc_tag_attributes'] != '') {
392 $tagAttributes = $tagAttributes . sprintf(' %s',$CODOC_SETTINGS['codoc_tag_attributes']);
393 }
394
395 $codoc_tag = preg_replace('/<((?:span|div)[^>]+)data-id="[^"]+"((?:[^>]+|))>/','<${1} ${2} data-without-body="1" id=' . $entryCodeFormated . $tagAttributes . ">", $matches[1]);
396 # THE THOR の page-lp.php が " " をけずるための対策
397 # "div class" -> "div class"
398 $codoc_tag = preg_replace('/div +class/','div class',$codoc_tag);
399
400 if ($params['is_amp_endpoint']) {
401 $format = preg_replace_callback('/(<(?:span|div)[^>]+>)((?:[^<>]+|))(<\/(?:span|div)>)/',function($matches) {
402 $format = $matches[1] . '<a href="%%s">%s</a>' . $matches[3];
403 return sprintf($format,($matches[2] ? $matches[2] : '続きを読む'));
404 },$codoc_tag);
405 $codoc_tag = sprintf($format,$params["post_permalink"]);
406 }
407
408 # タグの前後にHTMLを挿�
409
410 if (!isset($CODOC_SETTINGS['str_before_codoc_tag'])) {
411 $CODOC_SETTINGS['str_before_codoc_tag'] = '';
412 }
413 if (!isset($CODOC_SETTINGS['str_after_codoc_tag'])) {
414 $CODOC_SETTINGS['str_after_codoc_tag'] = '';
415 }
416 // 無料部分のみ表示
417 $post_content = $splited[0] . sprintf(
418 '%s<div class="wp-block-codoc-codoc-block">%s</div>%s',
419 $CODOC_SETTINGS['str_before_codoc_tag'],
420 $codoc_tag,
421 $CODOC_SETTINGS['str_after_codoc_tag']
422 );
423 // ::CODOC_WP_END_PAYWALL:: の後を足す
424 if (isset($before_splited[1]) and $before_splited[1]) {
425 $post_content .= $before_splited[1];
426 }
427 return $post_content;
428 }
429 /*
430
431 // Cookieの中のトークンを取得
432 $_CODOC->util->get_paywall_token_code();
433
434 */
435 function get_paywall_token_code() {
436 if (isset($_COOKIE['codocTokenCode']) and $codocTokenCode = $_COOKIE['codocTokenCode']) {
437 return $codocTokenCode;
438 }
439 return null;
440 }
441 /*
442
443 $_CODOC->util->check_login($mode); // cookie / strict
444
445 $response = $_CODOC->util->check_login('strict_with_data');
446 if ($response->status and $response->user) {
447 echo $reponse->user->code;
448 }
449
450 */
451 function check_login($mode = 'cookie') {
452 if ($codocTokenCode = $this->get_paywall_token_code()) {
453 if ($mode == 'cookie') {
454 // cookieの中にtokenがあればOK
455 return true;
456 }
457 if ($mode == 'strict' or $mode == 'strict_with_data') {
458 // ログイン状�
459 �を問い合わせ
460 $res = $this->callPaywallAPI('GET','/users',["paywall_token_code" => $codocTokenCode ]);
461 if ($res->status) {
462 if ($mode == 'strict_with_data') {
463 return $res;
464 } else {
465 return true;
466 }
467 } else {
468 return false;
469 }
470 }
471 }
472 return false;
473 }
474 /*
475
476 $_CODOC->util->check_owned($entry_code);
477
478 */
479 function check_owned($entry_code = null) {
480 if (!$entry_code) {
481 return false;
482 }
483 $res = $this->callPaywallAPI('GET','/entries/' . $entry_code, ["paywall_token_code" => $this->get_paywall_token_code(), "check_owned" => 1 ]);
484 if ($res->status) {
485 return true;
486 }
487 return false;
488 }
489
490 /*
491 $_CODOC->util->health_check();
492 */
493 function health_check() {
494 $sslverify = true;
495 $host = $this->codoc_url;
496 if (preg_match('/local/',$this->codoc_url)) {
497 $sslverify = false;
498 $host = 'https://host.docker.internal';
499 }
500 $url = sprintf("%s/codoc_health_check",$host);
501 $http = new WP_Http();
502 try {
503 $response = $http->request(
504 $url,
505 [
506 'sslverify' => $sslverify,
507 'method' => 'GET',
508 'timeout' => 10,
509 'headers' => [],
510 'body' => [],
511 ]
512 );
513 } catch(Exception $e) {
514
515 }
516 if ($response and $response['response']['code'] == '200') {
517 return true;
518 } else {
519 return null;
520 }
521 }
522 }
523
524