Skip to content

Commit 98c9500

Browse files
authored
Merge pull request #14 from sakots/dev
Dev marge
2 parents d90f335 + 0c0255f commit 98c9500

26 files changed

+2150
-615
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ $pallets_dat = array(['標準','palette.txt'],['PCCS_HSL','p_PCCS.txt'],['マン
6969

7070
[すべての履歴はこちら](changelog.md)
7171

72+
### [2025/05/28] v1.6.7
73+
74+
- Misskey連携機能追加
75+
- コード可読性アップ
76+
7277
### [0225/04/13] License
7378

7479
- sns_share Copyright (c)satopian 2023-2025 MIT License 追加

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## すべての履歴
44

5+
### [2025/05/28] v1.6.7
6+
7+
- Misskey連携機能追加
8+
- コード可読性アップ
9+
510
### [0225/04/13] License
611

712
- sns_share Copyright (c)satopian 2023-2025 MIT License 追加

noreita/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Each module is subject to its own license
66

77
BladeOne - Copyright (C) 2016-2025 Jorge Patricio Castro Castillo (The MIT License)
88
PaintBBS NEO - Copyright (C) 2017-2025 funige
9-
sns_share.inc.php - Copyright (c) 2023-2025 satopian MIT License
9+
sns_share.inc.php,connect_misskey_api - Copyright (c) 2023-2025 satopian MIT License
1010
DynamicPalette - Copyright (C) 2005 noraneko
1111
AppletFit - Copyright (C) 2019 Soto
1212
PaintBBS, Shi-Painter, PCH Viewer - Copyright (C) 2004 shi-chan

noreita/config.example.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
//設置URL phpのあるディレクトリの'/'まで
2727
//シェアボタンなどで使用
28+
//misskey連携では正しいURL必須
2829
define('BASE', 'https://example.com/noreita/');
2930

3031
//掲示板のタイトル(<title>とTOP)

noreita/connect_misskey_api.php

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
<?php
2+
//Petit Note 2021-2025 (c)satopian MIT Licence
3+
//https://paintbbs.sakura.ne.jp/
4+
5+
//Misskey APIに接続
6+
7+
require_once(__DIR__.'/config.php');
8+
require_once(__DIR__.'/functions.php');
9+
10+
$lang = ($http_langs = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '')
11+
? explode( ',', $http_langs )[0] : '';
12+
$en= (stripos($lang,'ja')!==0);
13+
14+
session_sta();
15+
16+
if((!isset($_SESSION['sns_api_session_id'])) || (!isset($_SESSION['sns_api_val']))) {
17+
die("Error: セッションがありません。Misskey投稿フローが正しく動作していません。");
18+
};
19+
20+
$baseUrl = $_SESSION['misskey_server_radio'] ?? "";
21+
if(!filter_var($baseUrl,FILTER_VALIDATE_URL)){
22+
die("Error: サーバのURLが無効です。: " . $baseUrl);
23+
}
24+
25+
$skip_auth_check = (bool)filter_input_data('GET','skip_auth_check',FILTER_VALIDATE_BOOLEAN);
26+
if($skip_auth_check){
27+
if((string)filter_input_data('GET','s_id') !== $_SESSION['sns_api_session_id']){
28+
die("Error: " . ($en ? "Operation failed." :"失敗しました。"));
29+
}
30+
return connect_misskey_api::create_misskey_note();
31+
}
32+
33+
connect_misskey_api::mi_auth_check();
34+
35+
// 認証チェック
36+
class connect_misskey_api{
37+
38+
public static function mi_auth_check(): void {
39+
global $en,$baseUrl;
40+
$sns_api_session_id = $_SESSION['sns_api_session_id'];
41+
$checkUrl = $baseUrl . "/api/miauth/{$sns_api_session_id}/check";
42+
43+
$checkCurl = curl_init();
44+
curl_setopt($checkCurl, CURLOPT_URL, $checkUrl);
45+
curl_setopt($checkCurl, CURLOPT_POST, true);
46+
curl_setopt($checkCurl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
47+
curl_setopt($checkCurl, CURLOPT_POSTFIELDS, json_encode([]));//空のData
48+
curl_setopt($checkCurl, CURLOPT_RETURNTRANSFER, true);
49+
50+
$checkResponse = curl_exec($checkCurl);
51+
curl_close($checkCurl);
52+
53+
if (!$checkResponse) {
54+
die("Error: " . ($en ? "Authentication failed." :"認証に失敗しました。") . " (Curl error)");
55+
}
56+
57+
$responseData = json_decode($checkResponse, true);
58+
if(!isset($responseData['token'])){
59+
die("Error: " . ($en ? "Authentication failed." :"認証に失敗しました。") . " (No token in response)");
60+
}
61+
$accessToken = $responseData['token'];
62+
$_SESSION['accessToken'] = $accessToken;
63+
$user = $responseData['user'];
64+
self::create_misskey_note();
65+
}
66+
67+
public static function create_misskey_note(): void {
68+
69+
global $en,$baseUrl,$root_url;
70+
71+
$accessToken = $_SESSION['accessToken'] ?? "";
72+
if(!$accessToken){
73+
die("Error: " . ($en ? "Authentication failed." :"認証に失敗しました。") . " (No access token)");
74+
}
75+
76+
list($com,$src_image,$tool,$painttime,$hide_thumbnail,$no,$article_url_link,$cw) = $_SESSION['sns_api_val'];
77+
78+
$src_image=basename($src_image);
79+
80+
// 画像のアップロード
81+
$imagePath = __DIR__.'/src/'.$src_image;
82+
83+
if(!is_file($imagePath)){
84+
die("Error: " . ($en ? "Image does not exist." : "画像がありません。") . ": " . $imagePath);
85+
};
86+
87+
$uploadUrl = $baseUrl . "/api/drive/files/create";
88+
$uploadHeaders = array(
89+
'Content-Type: multipart/form-data'
90+
);
91+
$uploadFields = array(
92+
'i' => $accessToken,
93+
'file' => new CURLFile($imagePath),
94+
);
95+
$uploadCurl = curl_init();
96+
curl_setopt($uploadCurl, CURLOPT_URL, $uploadUrl);
97+
curl_setopt($uploadCurl, CURLOPT_POST, true);
98+
curl_setopt($uploadCurl, CURLOPT_POSTFIELDS, $uploadFields);
99+
curl_setopt($uploadCurl, CURLOPT_RETURNTRANSFER, true);
100+
101+
$uploadResponse = curl_exec($uploadCurl);
102+
$uploadStatusCode = curl_getinfo($uploadCurl, CURLINFO_HTTP_CODE);
103+
$curlError = curl_error($uploadCurl);
104+
curl_close($uploadCurl);
105+
106+
if ($uploadResponse === false) {
107+
die("Error: 画像のアップロードに失敗しました (cURL Error: " . $curlError . ")");
108+
}
109+
110+
$responseData = json_decode($uploadResponse, true);
111+
112+
if ($uploadStatusCode !== 200 && $uploadStatusCode !== 204) {
113+
$errorDetails = isset($responseData['error']['message']) ? $responseData['error']['message'] : 'Unknown API Error';
114+
die("Error: 画像のアップロードに失敗しました (API Status: " . $uploadStatusCode . ", Details: " . $errorDetails . ")");
115+
}
116+
117+
$fileId = $responseData['id'] ?? '';
118+
119+
if(!$fileId){
120+
die("Error: " . ($en ? "Failed to upload the image." : "画像のアップロードに失敗しました。") . " (No file ID in response)");
121+
}
122+
123+
$updateUrl = $baseUrl . "/api/drive/files/update";
124+
$updateHeaders = array(
125+
'Content-Type: application/json'
126+
);
127+
$updateData = array(
128+
'i' => $accessToken,
129+
'fileId' => $fileId,
130+
'isSensitive' => (bool)($hide_thumbnail),
131+
);
132+
133+
$updateCurl = curl_init();
134+
curl_setopt($updateCurl, CURLOPT_URL, $updateUrl);
135+
curl_setopt($updateCurl, CURLOPT_POST, true);
136+
curl_setopt($updateCurl, CURLOPT_HTTPHEADER, $updateHeaders);
137+
curl_setopt($updateCurl, CURLOPT_POSTFIELDS, json_encode($updateData));
138+
curl_setopt($updateCurl, CURLOPT_RETURNTRANSFER, true);
139+
$updateResponse = curl_exec($updateCurl);
140+
$updateStatusCode = curl_getinfo($updateCurl, CURLINFO_HTTP_CODE);
141+
$updateCurlError = curl_error($updateCurl);
142+
curl_close($updateCurl);
143+
144+
if ($updateResponse === false) {
145+
die("Error: ファイルの更新に失敗しました (cURL Error: " . $updateCurlError . ")");
146+
}
147+
if ($updateStatusCode !== 200 && $updateStatusCode !== 204) {
148+
$updateResponseData = json_decode($updateResponse, true);
149+
$errorDetails = isset($updateResponseData['error']['message']) ? $updateResponseData['error']['message'] : 'Unknown API Error';
150+
die("Error: ファイルの更新に失敗しました (API Status: " . $updateStatusCode . ", Details: " . $errorDetails . ")");
151+
}
152+
153+
$uploadResult = json_decode($uploadResponse, true);
154+
155+
if (!$fileId) {
156+
die("Error: " . ($en ? "Failed to post the content." : "投稿に失敗しました。") . " (No file ID in response)");
157+
}
158+
159+
sleep(10);
160+
161+
$tool= $tool ? 'Tool:'.$tool."\n" :'';
162+
$painttime= $painttime ? 'Paint time:'.$painttime."\n" :'';
163+
164+
$src_image_filename = pathinfo($src_image, PATHINFO_FILENAME );//拡張子除去
165+
166+
$fixed_link = BASE.'?resno='.$no.'#'.$src_image_filename;
167+
$fixed_link = filter_var($fixed_link,FILTER_VALIDATE_URL) ? $fixed_link : '';
168+
$article_url_link = $article_url_link ? $fixed_link : '';
169+
$com=str_replace(["\r\n","\r"],"\n",$com);
170+
$com=$com ? $com."\n" :'';
171+
$com = preg_replace("/(\s*\n){2,}/u","\n",$com); //不要改行カット
172+
173+
$status = $tool.$painttime.$com.$article_url_link;
174+
175+
$postUrl = $baseUrl . "/api/notes/create";
176+
$postHeaders = array(
177+
'Content-Type: application/json'
178+
);
179+
$postData = array(
180+
'i' => $accessToken,
181+
'cw' => $cw,
182+
'text' => $status,
183+
'fileIds' => array($fileId),
184+
);
185+
186+
$postCurl = curl_init();
187+
curl_setopt($postCurl, CURLOPT_URL, $postUrl);
188+
curl_setopt($postCurl, CURLOPT_POST, true);
189+
curl_setopt($postCurl, CURLOPT_HTTPHEADER, $postHeaders);
190+
curl_setopt($postCurl, CURLOPT_POSTFIELDS, json_encode($postData));
191+
curl_setopt($postCurl, CURLOPT_RETURNTRANSFER, true);
192+
$postResponse = curl_exec($postCurl);
193+
$postStatusCode = curl_getinfo($postCurl, CURLINFO_HTTP_CODE);
194+
$postCurlError = curl_error($postCurl);
195+
curl_close($postCurl);
196+
197+
if ($postResponse === false) {
198+
die("Error: Misskeyへの投稿に失敗しました (cURL Error: " . $postCurlError . ")");
199+
}
200+
201+
if ($postStatusCode !== 200 && $postStatusCode !== 204) {
202+
$postResponseData = json_decode($postResponse, true);
203+
$errorDetails = isset($postResponseData['error']['message']) ? $postResponseData['error']['message'] : 'Unknown API Error';
204+
die("Error: Misskeyへの投稿に失敗しました (API Status: " . $postStatusCode . ", Details: " . $errorDetails . ")");
205+
}
206+
207+
$postResult = json_decode($postResponse, true);
208+
if (!empty($postResult['createdNote']["fileIds"])) {
209+
210+
unset($_SESSION['sns_api_session_id']);
211+
unset($_SESSION['sns_api_val']);
212+
unset($_SESSION['userdel']);
213+
214+
redirect(BASE.'?mode=misskey_success&no='.$no);
215+
}
216+
else {
217+
die("Error: " . ($en ? "Failed to post the content." : "投稿に失敗しました。") . " (API response missing createdNote)");
218+
}
219+
}
220+
}

0 commit comments

Comments
 (0)