https://sl-memo.blogspot.com/
date_default_timezone_set('Asia/Tokyo');
$UAstring = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0";
//入力データ
$readfile = "text_data.txt";
//$readdata = explode("\n", file_get_contents($readfile));
//テスト用なので固定の配列で記述
$readdata = array(
'001<->IMG - 3<->https://www.flickr.com/photos/153589246@N07/37182374834/<->https://live.staticflickr.com/4459/37182374834_a89ca42e10_c.jpg'
,'002<->Baby Anythings are Cute<->https://www.flickr.com/photos/dennissylvesterhurd/52852294515/<->https://live.staticflickr.com/65535/52852294515_b00fb1e17d_c.jpg'
,'003<->Labradoodle<->https://www.flickr.com/photos/195591092@N07/52064576115/<->https://live.staticflickr.com/65535/52064576115_636e0487bf_c.jpg'
,'004<->Day with Monty 1<->https://www.flickr.com/photos/ianlivesey/49847245082/<->https://live.staticflickr.com/65535/49847245082_41ca62b972_c.jpg'
);
$counter = 0;
//Bluesky接続 (Json Web Token (JWT) 取得)
$handle = "**********************"; //あなたのBluesky ID (username.bsky.social など)
$password = "**********************"; //あなたのBluesky パスワード
$jwt = NULL;
$connect_FLG = false;
$logfile = "text_test.log";
$log_FLG = false;
//Main処理
//各行毎で処理する
foreach($readdata as $lines) {
$items = explode("<->", $lines);// 0=番号, 1=タイトル, 2=URL, 3=imageURL
//画像URLの無いものは破棄
if(!(isset($items[3]))) continue;
if(!$connect_FLG){
$connect_FLG = true;
// Json Web Token (JWT) 取得
$jwt = login($handle, $password);
}
//-----------------------------------------------------------------------------------------------
//Blusky 投稿
$title= (string)$items[1];
$link = (string)$items[2];
$image= (string)$items[3];
$text = $title . " #Flickr #PublicDomain \n" . $link;
$facets = [];
//この辺の facets でのタグ付けやLink付けを丸投げでやってくれるライブラリーもあるらしい
//Linkを付ける
$linkStart = strpos($text, $link);
$linkEnd = $linkStart + strlen($link);
$facets[] = [
'index' => [
'byteStart' => $linkStart,
'byteEnd' => $linkEnd
],
'features' => [
[
'$type' => 'app.bsky.richtext.facet#link',
'uri' => $link
]
]
];
//HashTagを付ける
$tagstring = "#Flickr";// # を含む
$linkStart = strpos($text, $tagstring);
$linkEnd = $linkStart + strlen($tagstring);
$facets[] = [
'index' => [
'byteStart' => $linkStart,
'byteEnd' => $linkEnd
],
'features' => [
[
'$type' => 'app.bsky.richtext.facet#tag',
'tag' => "Flickr" // # を含まない
]
]
];
$tagstring = "#PublicDomain";// # を含む
$linkStart = strpos($text, $tagstring);
$linkEnd = $linkStart + strlen($tagstring);
$facets[] = [
'index' => [
'byteStart' => $linkStart,
'byteEnd' => $linkEnd
],
'features' => [
[
'$type' => 'app.bsky.richtext.facet#tag',
'tag' => "PublicDomain" // # を含まない
]
]
];
$record = [
'$type' => "app.bsky.feed.post",
'text' => $text,
'createdAt' => (new DateTime())->format("c"),
'facets' => $facets,
];
//画像データ取得とUpload
$imageUri = uploadImage($jwt, $image);
$record['embed'] = [
'$type' => 'app.bsky.embed.external',
'external'=> [
'uri' => $link, //リンクカードのURL
'title' => $title,
'description' => 'Blog記事用のネタ投稿です。descriptionは省略可。titleは省略するとurlになるよ',
'thumb' => $imageUri,
],
];
$response = post_w_link($handle, $jwt, $record);
file_put_contents($logfile,print_r($response,true),$log_FLG);
if(!$log_FLG) $log_FLG = FILE_APPEND;
if(isset($response['validationStatus'])){
if($response['validationStatus'] == 'valid'){
//投稿成功
$counter++;
}
}
//-----------------------------------------------------------------------------------------------
usleep(100000 * 3);//0.1秒 x N停止 (sleep 1秒 = usleep 1000000)
}
echo "total : " . (string)$counter ." items post\n";
/////////////////////////////////////////////////////////////////
function login($handle, $password)
{
$ch = curl_init("https://bsky.social/xrpc/com.atproto.server.createSession");
curl_setopt_array($ch, [
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 1000,
CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_POST => true,
CURLOPT_USERAGENT => $GLOBALS['UAstring'],
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"identifier" => $handle,
"password" => $password,
]),
]);
$response = curl_exec($ch);
if(curl_error($ch)){
echo "login error : " . curl_error($ch) . "\n";
die();
}
curl_close($ch);
$responseJson = json_decode($response, true);
if(isset($responseJson["accessJwt"])){
return $responseJson["accessJwt"];
}else{
print_r($responseJson);
}
}
function post_w_link($handle, $jwt, $record)
{
$ch = curl_init("https://bsky.social/xrpc/com.atproto.repo.createRecord");
curl_setopt_array($ch, [
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 1000,
CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_POST => true,
CURLOPT_USERAGENT => $GLOBALS['UAstring'],
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Authorization: Bearer {$jwt}",
],
CURLOPT_POSTFIELDS => json_encode([
"repo" => $handle,
"collection" => "app.bsky.feed.post",
"record" => $record,
]),
]);
$response = curl_exec($ch);
if(curl_error($ch)){
echo "post error : " . curl_error($ch) . "\n";
die();
}
curl_close($ch);
$responseJson = json_decode($response, true);
return $responseJson;
}
function uploadImage($jwt, $imagePath)
{
$imageData = file_get_contents($imagePath);
// $mime = mime_content_type($imagePath);
//Flickr は形式固定なのでローカル保存しない
//他サイト等て混在する場合は一時的にローカル環境に出力してmime_content_typeで判別
$mime = 'image/jpeg';
$ch = curl_init("https://bsky.social/xrpc/com.atproto.repo.uploadBlob");
curl_setopt_array($ch, [
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_MAXREDIRS => 1000,
CURLOPT_COOKIEJAR => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_COOKIEFILE => dirname(__FILE__) . '/cookie_bsky.txt',
CURLOPT_POST => true,
CURLOPT_USERAGENT => $GLOBALS['UAstring'],
CURLOPT_HTTPHEADER => [
"Content-Type: $mime",
"Authorization: Bearer {$jwt}",
],
CURLOPT_POSTFIELDS => $imageData,
]);
$response = curl_exec($ch);
if(curl_error($ch)){
echo "upload error : " . curl_error($ch) . "\n";
die();
}
curl_close($ch);
$responseJson = json_decode($response, true);
return $responseJson['blob'] ?? null; //PHP 7.x 以降要
/*
3項演算の亜種
$x ?? $y; は
isset($x) ? $x : $y; と同じ効果です(PHP 7.x以上)
*/
}
?>