PluginProbe
codoc / 0.9.61
codoc v0.9.61
0.9.61 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 All 115 releases
← All changes | class-codoc-util.php +236 -13 0.9.8.9 → 0.9.61 View file →
@@ -6,10 +6,15 @@
6 6
7 7 if (!defined('CODOC_URL')) {
8 8 define( 'CODOC_URL', 'https://codoc.jp' );
9 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 +}
10 16
11 -require_once( ABSPATH . WPINC . '/class-http.php');
12 17 require_once( ABSPATH . WPINC . '/class-wp-error.php');
13 18
14 19 final class CodocUtil {
15 20 public $codoc_url = CODOC_URL;
@@ -45,8 +50,14 @@
45 50 'headers' => $headers,
46 51 'body' => $body,
47 52 ]
48 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 + }
49 60 if ( is_wp_error($response) || $response['response']['code'] != 200 ) {
50 61 //何もしない
51 62 //var_dump( $response );
52 63 }
@@ -62,8 +73,49 @@
62 73 } else {
63 74 return null;
64 75 }
65 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 + }
66 118 public function setAuthInfo($params = [ "usercode" => null, "token" => null ]) {
67 119 if ($params["usercode"]) {
68 120 $this->usercode = $params["usercode"];
69 121 }
@@ -83,8 +135,38 @@
83 135 public function get_support_entry($params = [] ,$auth_info = ["usercode" => null, "token" => null]) {
84 136 $this->setAuthInfo($auth_info);
85 137 return $this->callAPI('GET','/support_entry');
86 138 }
139 + // API側と統一した文字数上限のバリデーション。エラーメッセージの配列を返す (エラー無しなら空配列)
140 + public function validate_entry_lengths($api_params) {
141 + $errors = [];
142 + $title = isset($api_params['title']) ? $api_params['title'] : '';
143 + $body_free = isset($api_params['body_free']) ? $api_params['body_free'] : '';
144 + $body_paywalled = isset($api_params['body_paywalled']) ? $api_params['body_paywalled'] : '';
145 + $binded_url = isset($api_params['binded_url']) ? $api_params['binded_url'] : '';
146 +
147 + if (mb_strlen($title) > CODOC_MAX_TITLE_LENGTH) {
148 + // Translators: %1$d is the max length, %2$d is the current length.
149 + $errors[] = sprintf(__('Title exceeds the maximum length of %1$d characters (current: %2$d).', 'codoc'), CODOC_MAX_TITLE_LENGTH, mb_strlen($title));
150 + }
151 + $len_body_free = mb_strlen($body_free);
152 + $len_body_paywalled = mb_strlen($body_paywalled);
153 + if ($len_body_free > CODOC_MAX_BODY_FREE_LENGTH) {
154 + $errors[] = sprintf(__('Free area exceeds the maximum length of %1$d characters (current: %2$d).', 'codoc'), CODOC_MAX_BODY_FREE_LENGTH, $len_body_free);
155 + }
156 + if ($len_body_paywalled > CODOC_MAX_BODY_PAYWALLED_LENGTH) {
157 + $errors[] = sprintf(__('Paid area exceeds the maximum length of %1$d characters (current: %2$d).', 'codoc'), CODOC_MAX_BODY_PAYWALLED_LENGTH, $len_body_paywalled);
158 + }
159 + $len_body_total = $len_body_free + $len_body_paywalled;
160 + if ($len_body_total > CODOC_MAX_BODY_LENGTH) {
161 + $errors[] = sprintf(__('Total body exceeds the maximum length of %1$d characters (current: %2$d).', 'codoc'), CODOC_MAX_BODY_LENGTH, $len_body_total);
162 + }
163 + if (mb_strlen($binded_url) > CODOC_MAX_BINDED_URL_LENGTH) {
164 + $errors[] = sprintf(__('URL exceeds the maximum length of %1$d characters (current: %2$d).', 'codoc'), CODOC_MAX_BINDED_URL_LENGTH, mb_strlen($binded_url));
165 + }
166 + return $errors;
167 + }
168 +
87 169 public function sync_entry($params = [
88 170 "post_title" => null,
89 171 "post_content" => null,
90 172 "post_status" => null, # 0, 1
@@ -109,10 +191,17 @@
109 191 return;
110 192 }
111 193 // TODO: split or html parse? HTMLがつながってる場合はおかしくなる
112 194 // classic(tinymce)版の場合p、もしくはdivにかこまれている
195 + $end_tag_regex = '/<(?:div|p)>::CODOC_WP_END_PAYWALL::<\/(?:div|p)>/';
196 + $before_splited = preg_split($end_tag_regex,$post_content);
197 + $post_content = $before_splited[0];
113 198 $splited = preg_split('/(?:<(?:div|p)(?:[^>]+|)>|)<\!-- +wp:codoc\/codoc-block .*<\!-- +\/wp:codoc\/codoc-block +-->(?:<\/(?:div|p)>|)/s',$post_content);
114 - $status = $params['post_status'];
199 + $status = $params['post_status']; # 0: 非公開 1: 公開 2:限定公開(パスワードの場合は限定公開で同期する)
200 + // codoc設定で限定公開を有効で、公開の場合は 限定公開にする
201 + if ($status == 1 and isset($codoc_info['statusLimited']) and $codoc_info['statusLimited']) {
202 + $status = 2;
203 + }
115 204 # $body_free = '';
116 205 # $body_paywalled = '';
117 206 # if (count($splited) >= 2) {
118 207 #
@@ -138,10 +227,21 @@
138 227 'limited_count' => isset($codoc_info['limitedCount']) ? $codoc_info['limitedCount'] : 1,
139 228 'affiliate_mode' => isset($codoc_info['affiliateMode']) ? ($codoc_info['affiliateMode'] ? 1 : 0) : 0,
140 229 'affiliate_rate' => isset($codoc_info['affiliateRate']) ? $codoc_info['affiliateRate'] : '0.0500',
141 230 'show_support' => isset($codoc_info['showSupport']) ? ($codoc_info['showSupport'] ? 1 : 0) : 0,
231 + 'show_paywalled_support' => isset($codoc_info['showPaywalledSupport']) ? ($codoc_info['showPaywalledSupport'] ? 1 : 0) : 0,
142 232 'subscriptions' => isset($codoc_info['subscriptions']) ? array_keys($codoc_info['subscriptions']) : [],
143 233 ];
234 + // ゲスト購入の可否 (未設定 = 旧バージョンのブロックの場合は送信せず本体側の既存値を維持)
235 + if (isset($codoc_info['showPayWithoutAccountButton'])) {
236 + $api_params['show_pay_without_account_button'] = $codoc_info['showPayWithoutAccountButton'] ? 1 : 0;
237 + }
238 + // API側と統一した文字数バリデーション
239 + $errors = $this->validate_entry_lengths($api_params);
240 + if ($errors) {
241 + set_transient('codoc_entry_validation_errors', $errors, MINUTE_IN_SECONDS * 5);
242 + return null;
243 + }
144 244 $entryCode = $params['codoc_entry_code'];
145 245 $res = null;
146 246 if ($entryCode) {
147 247 $res = $this->callAPI('PUT','/entries/' . $entryCode ,$api_params);
@@ -230,19 +330,39 @@
230 330 $show_support_location = 'bottom';
231 331 if (isset($CODOC_SETTINGS['show_support_location'])) {
232 332 $show_support_location = $CODOC_SETTINGS['show_support_location'];
233 333 }
234 -
334 + // デフォルト値をうめておく
335 + if (!isset($CODOC_SETTINGS['support_button_text'])) {
336 + $CODOC_SETTINGS['support_button_text'] = 'サポートする';
337 + }
338 + if (!isset($CODOC_SETTINGS['show_like'])) {
339 + $CODOC_SETTINGS['show_like'] = 1;
340 + }
341 + if (!isset($CODOC_SETTINGS['show_about_codoc'])) {
342 + $CODOC_SETTINGS['show_about_codoc'] = 1;
343 + }
344 + if (!isset($CODOC_SETTINGS['show_powered_by'])) {
345 + $CODOC_SETTINGS['show_powered_by'] = 1;
346 + }
347 + if (!isset($CODOC_SETTINGS['show_created_by'])) {
348 + $CODOC_SETTINGS['show_created_by'] = 1;
349 + }
350 + if (!isset($CODOC_SETTINGS['show_copyright'])) {
351 + $CODOC_SETTINGS['show_copyright'] = 1;
352 + }
235 353 $show_support_entry = (is_single() && preg_grep("/(?:$show_support_categories)/",array_map( function($c) { return $c->name; },get_the_category(get_post()->ID))));
236 354 if (!$matches && ($support_entry_code = $params['codoc_support_entry_code']) && $show_support_entry) {
237 355 $support_tag = sprintf(
238 - '<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"></div>',
356 + '<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>',
239 357 htmlspecialchars($show_support_message,ENT_QUOTES),
240 358 $support_entry_code,
241 359 $CODOC_SETTINGS['support_button_text'],
242 360 $CODOC_SETTINGS['show_like'],
243 361 $CODOC_SETTINGS['show_about_codoc'],
244 - $CODOC_SETTINGS['show_powered_by']
362 + $CODOC_SETTINGS['show_powered_by'],
363 + $CODOC_SETTINGS['show_created_by'],
364 + $CODOC_SETTINGS['show_copyright']
245 365 );
246 366 $post_content = $show_support_location == 'bottom' ?
247 367 $post_content . $support_tag :
248 368 $support_tag . $post_content ;
@@ -254,14 +374,17 @@
254 374 }
255 375
256 376 // codocタグで分割 (202001: gutenbergで直前のdivタグを削除)
257 377 $tag_regex = '/(?:<div(?:[^>]+|)>|)<(?:span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:span|div)>(?:<\/div>|)/';
378 + $end_tag_regex = '/<(?:div|p)>::CODOC_WP_END_PAYWALL::<\/(?:div|p)>/';
258 379 if ( $params['preview'] ) {
259 380 $post_content = preg_replace($tag_regex,'<div class="codoc-continue">ここから上は無料で表示されます</div>',$post_content);
381 + $post_content = preg_replace($end_tag_regex,'<div class="codoc-continue">ここから下は無料で表示されます</div>',$post_content);
260 382 return $post_content;
261 383 }
262 384 // codoc タグの前後で分ける
263 - $splited = preg_split($tag_regex,$post_content);
385 + $before_splited = preg_split($end_tag_regex,$post_content);
386 + $splited = preg_split($tag_regex,$before_splited[0]);
264 387 // codoc タグにID属性のentrycodeとdata-without-body(無料分を非表示)をつける
265 388 $entryCodeFormated = sprintf('"codoc-entry-%s" ',$params['codoc_entry_code']);
266 389
267 390 // 文言系の設定をつける
@@ -274,24 +397,30 @@
274 397 }
275 398 if (isset($CODOC_SETTINGS['show_powered_by']) and $CODOC_SETTINGS['show_powered_by'] != 1) {
276 399 $tagAttributes = $tagAttributes . sprintf(' data-show-powered-by="%s"',$CODOC_SETTINGS['show_powered_by']);
277 400 }
278 - if ($CODOC_SETTINGS['entry_button_text']) {
401 + if (isset($CODOC_SETTINGS['show_created_by']) and $CODOC_SETTINGS['show_created_by'] != 1) {
402 + $tagAttributes = $tagAttributes . sprintf(' data-show-created-by="%s"',$CODOC_SETTINGS['show_created_by']);
403 + }
404 + if (isset($CODOC_SETTINGS['show_copyright']) and $CODOC_SETTINGS['show_copyright'] != 1) {
405 + $tagAttributes = $tagAttributes . sprintf(' data-show-copyright="%s"',$CODOC_SETTINGS['show_copyright']);
406 + }
407 + if (isset($CODOC_SETTINGS['entry_button_text']) and $CODOC_SETTINGS['entry_button_text'] != '') {
279 408 $tagAttributes = $tagAttributes . sprintf(' data-entry-button-text="%s"',$CODOC_SETTINGS['entry_button_text']);
280 409 }
281 - if ($CODOC_SETTINGS['subscription_button_text']) {
410 + if (isset($CODOC_SETTINGS['subscription_button_text']) and $CODOC_SETTINGS['subscription_button_text'] != '') {
282 411 $tagAttributes = $tagAttributes . sprintf(' data-subscription-button-text="%s"',$CODOC_SETTINGS['subscription_button_text']);
283 412 }
284 - if ($CODOC_SETTINGS['support_button_text']) {
413 + if (isset($CODOC_SETTINGS['support_button_text']) and $CODOC_SETTINGS['support_button_text'] != '') {
285 414 $tagAttributes = $tagAttributes . sprintf(' data-support-button-text="%s"',$CODOC_SETTINGS['support_button_text']);
286 415 }
287 - if ($CODOC_SETTINGS['subscription_message']) {
416 + if (isset($CODOC_SETTINGS['subscription_message']) and $CODOC_SETTINGS['subscription_message'] != '') {
288 417 $tagAttributes = $tagAttributes . sprintf(' data-subscription-message="%s"',$CODOC_SETTINGS['subscription_message']);
289 418 }
290 - if ($CODOC_SETTINGS['support_message']) {
419 + if (isset($CODOC_SETTINGS['support_message']) and $CODOC_SETTINGS['support_message'] != '') {
291 420 $tagAttributes = $tagAttributes . sprintf(' data-support-message="%s"',$CODOC_SETTINGS['support_message']);
292 421 }
293 - if ($CODOC_SETTINGS['codoc_tag_attributes']) {
422 + if (isset($CODOC_SETTINGS['codoc_tag_attributes']) and $CODOC_SETTINGS['codoc_tag_attributes'] != '') {
294 423 $tagAttributes = $tagAttributes . sprintf(' %s',$CODOC_SETTINGS['codoc_tag_attributes']);
295 424 }
296 425
297 426 $codoc_tag = preg_replace('/<((?:span|div)[^>]+)data-id="[^"]+"((?:[^>]+|))>/','<${1} ${2} data-without-body="1" id=' . $entryCodeFormated . $tagAttributes . ">", $matches[1]);
@@ -320,10 +449,104 @@
320 449 $CODOC_SETTINGS['str_before_codoc_tag'],
321 450 $codoc_tag,
322 451 $CODOC_SETTINGS['str_after_codoc_tag']
323 452 );
453 + // ::CODOC_WP_END_PAYWALL:: の後を足す
454 + if (isset($before_splited[1]) and $before_splited[1]) {
455 + $post_content .= $before_splited[1];
456 + }
324 457 return $post_content;
325 458 }
459 + /*
326 460
327 -
461 + // Cookieの中のトークンを取得
462 + $_CODOC->util->get_paywall_token_code();
463 +
464 + */
465 + function get_paywall_token_code() {
466 + if (isset($_COOKIE['codocTokenCode']) and $codocTokenCode = $_COOKIE['codocTokenCode']) {
467 + return $codocTokenCode;
468 + }
469 + return null;
470 + }
471 + /*
472 +
473 + $_CODOC->util->check_login($mode); // cookie / strict
474 +
475 + $response = $_CODOC->util->check_login('strict_with_data');
476 + if ($response->status and $response->user) {
477 + echo $reponse->user->code;
478 + }
479 +
480 + */
481 + function check_login($mode = 'cookie') {
482 + if ($codocTokenCode = $this->get_paywall_token_code()) {
483 + if ($mode == 'cookie') {
484 + // cookieの中にtokenがあればOK
485 + return true;
486 + }
487 + if ($mode == 'strict' or $mode == 'strict_with_data') {
488 + // ログイン状態を問い合わせ
489 + $res = $this->callPaywallAPI('GET','/users',["paywall_token_code" => $codocTokenCode ]);
490 + if ($res->status) {
491 + if ($mode == 'strict_with_data') {
492 + return $res;
493 + } else {
494 + return true;
495 + }
496 + } else {
497 + return false;
498 + }
499 + }
500 + }
501 + return false;
502 + }
503 + /*
504 +
505 + $_CODOC->util->check_owned($entry_code);
506 +
507 + */
508 + function check_owned($entry_code = null) {
509 + if (!$entry_code) {
510 + return false;
511 + }
512 + $res = $this->callPaywallAPI('GET','/entries/' . $entry_code, ["paywall_token_code" => $this->get_paywall_token_code(), "check_owned" => 1 ]);
513 + if ($res->status) {
514 + return true;
515 + }
516 + return false;
517 + }
518 +
519 + /*
520 + $_CODOC->util->health_check();
521 + */
522 + function health_check() {
523 + $sslverify = true;
524 + $host = $this->codoc_url;
525 + if (preg_match('/local/',$this->codoc_url)) {
526 + $sslverify = false;
527 + $host = 'https://host.docker.internal';
528 + }
529 + $url = sprintf("%s/codoc_health_check",$host);
530 + $http = new WP_Http();
531 + try {
532 + $response = $http->request(
533 + $url,
534 + [
535 + 'sslverify' => $sslverify,
536 + 'method' => 'GET',
537 + 'timeout' => 10,
538 + 'headers' => [],
539 + 'body' => [],
540 + ]
541 + );
542 + } catch(Exception $e) {
543 +
544 + }
545 + if ($response and $response['response']['code'] == '200') {
546 + return true;
547 + } else {
548 + return null;
549 + }
550 + }
328 551 }
329 552