RSS’ten X (Twitter)’a PHP Botu

RSS akışınızı X (Twitter)’da paylaşan küçük bir PHP botu. OAuth 1.0a, cron, tek seferde bir öğe, anahtarsız örnek kod.

RSS zaten var; peki X’e otomatik nasıl atarız? Bu yazıda, RSS’ten aldığı yeni öğeyi metin olarak X API ile paylaşan, OAuth 1.0a kullanan çok küçük bir PHP betiği kuruyoruz. Her tetiklemede tek gönderi, basit bir state dosyası ile tekrarları engelleme ve cron ile zamanlama.

Kaynak : RSS to X (Twitter)

Kod (anahtarsız, paylaşılabilir)

<?php
// rss-to-x.php (TR anlatım, key-free)
date_default_timezone_set('Europe/Istanbul');
$config = require __DIR__.'/.env.php';
@mkdir(__DIR__.'/data', 0777, true);

function hmac_sha1($data,$key){ return base64_encode(hash_hmac('sha1',$data,$key,true)); }
function build_oauth_header($p){ ksort($p); $v=[]; foreach($p as $k=>$x){ $v[]=$k.'="'.rawurlencode($x).'"'; } return 'OAuth '.implode(', ', $v); }
function http_post_json($url,$headers,$json){
$ch=curl_init($url);
curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,
CURLOPT_HTTPHEADER=>array_merge(['Content-Type: application/json'],$headers),
CURLOPT_POSTFIELDS=>json_encode($json, JSON_UNESCAPED_UNICODE),
CURLOPT_TIMEOUT=>30, CURLOPT_USERAGENT=>'rss-to-x-bot/1.0']);
$res=curl_exec($ch); if($res===false) throw new Exception(curl_error($ch));
$code=curl_getinfo($ch, CURLINFO_RESPONSE_CODE); curl_close($ch); return [$code,$res];
}
function sign_oauth1($method,$url,$params,$ck,$cs,$t,$ts){
$base=$params; ksort($base);
$s=strtoupper($method).'&'.rawurlencode($url).'&'.rawurlencode(http_build_query($base,'','&',PHP_QUERY_RFC3986));
$key=rawurlencode($cs).'&'.rawurlencode($ts);
$params['oauth_signature']=hmac_sha1($s,$key);
return $params;
}

// 1) RSS
$feed = @simplexml_load_file($config['FEED_URL']); if(!$feed){ die("RSS hatası"); }
$items=[]; foreach($feed->channel->item as $it){
$items[]=['guid'=>(string)($it->guid ?? $it->link),'title'=>trim((string)$it->title),
'link'=>trim((string)$it->link),'date'=>strtotime((string)$it->pubDate ?: 'now')];
}
usort($items, fn($a,$b)=>$a['date'] <=> $b['date']);

// 2) State (tekrar kontrolü)
$stateFile=$config['STATE_FILE'];
$state=file_exists($stateFile)?json_decode(file_get_contents($stateFile),true):[];
if(!is_array($state)) $state=[];

// 3) İlk görülmeyeni paylaş
foreach($items as $it){
if(isset($state[$it['guid']])) continue;

$hashtags=['#haber','#otomasyon','#php']; // düzenle
$suffix=' '.$it['link'].' '.implode(' ',$hashtags);
$max=280; $base=$it['title']; $maxTitle=$max - mb_strlen($suffix); if($maxTitle<1) $maxTitle=1;
if(mb_strlen($base)>$maxTitle) $base=mb_substr($base,0,$maxTitle-1).'…';
$text=$base.$suffix;

$endpoint='https://api.twitter.com/2/tweets'; // veya https://api.x.com/2/tweets
$oauth=['oauth_consumer_key'=>$config['API_KEY'],'oauth_nonce'=>bin2hex(random_bytes(8)),
'oauth_signature_method'=>'HMAC-SHA1','oauth_timestamp'=>time(),
'oauth_token'=>$config['ACCESS_TOKEN'],'oauth_version'=>'1.0'];

$signed=sign_oauth1('POST',$endpoint,$oauth,$config['API_KEY'],$config['API_KEY_SECRET'],
$config['ACCESS_TOKEN'],$config['ACCESS_TOKEN_SECRET']);

[$code,$res]=http_post_json($endpoint,['Authorization: '.build_oauth_header($signed)],['text'=>$text]);

if($code>=200 && $code<300){
$state[$it['guid']] = ['tweeted_at'=>date('c'),'text'=>$text];
@file_put_contents($stateFile, json_encode($state, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
echo "Tweet atıldı: ".$text."\n";
} else {
echo "Hata ($code): ".$res."\n";
}
break; // koşuya 1 öğe
}

 

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir