PluginProbe
codoc / 0.9.56
codoc v0.9.56
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.56, at class-codoc-util.php

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