PluginProbe
codoc / 0.9.50
codoc v0.9.50
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.50, at class-codoc-util.php

509 lines 21.2 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 */
440 function check_login($mode = 'cookie') {
441 if ($codocTokenCode = $this->get_paywall_token_code()) {
442 if ($mode == 'cookie') {
443 // cookieの中にtokenがあればOK
444 return true;
445 }
446 if ($mode == 'strict') {
447 // ログイン状�
448 �を問い合わせ
449 $res = $this->callPaywallAPI('GET','/users',["paywall_token_code" => $codocTokenCode ]);
450 if ($res->status) {
451 return true;
452 } else {
453 return false;
454 }
455 }
456 }
457 return false;
458 }
459 /*
460
461 $_CODOC->util->check_owned($entry_code);
462
463 */
464 function check_owned($entry_code = null) {
465 if (!$entry_code) {
466 return false;
467 }
468 $res = $this->callPaywallAPI('GET','/entries/' . $entry_code, ["paywall_token_code" => $this->get_paywall_token_code(), "check_owned" => 1 ]);
469 if ($res->status) {
470 return true;
471 }
472 return false;
473 }
474
475 /*
476 $_CODOC->util->health_check();
477 */
478 function health_check() {
479 $sslverify = true;
480 $host = $this->codoc_url;
481 if (preg_match('/local/',$this->codoc_url)) {
482 $sslverify = false;
483 $host = 'https://host.docker.internal';
484 }
485 $url = sprintf("%s/codoc_health_check",$host);
486 $http = new WP_Http();
487 try {
488 $response = $http->request(
489 $url,
490 [
491 'sslverify' => $sslverify,
492 'method' => 'GET',
493 'timeout' => 10,
494 'headers' => [],
495 'body' => [],
496 ]
497 );
498 } catch(Exception $e) {
499
500 }
501 if ($response and $response['response']['code'] == '200') {
502 return true;
503 } else {
504 return null;
505 }
506 }
507 }
508
509