Files
zuevav e5a88665cd mailn
2026-04-30 15:14:09 +03:00

273 lines
7.7 KiB
PHP

<?php
/**
* Flickr OAuth 1.0a Authentication
* Handles authorization flow to get access tokens for API calls
*/
class FlickrOAuth
{
private $consumerKey;
private $consumerSecret;
private $requestTokenUrl = 'https://www.flickr.com/services/oauth/request_token';
private $authorizeUrl = 'https://www.flickr.com/services/oauth/authorize';
private $accessTokenUrl = 'https://www.flickr.com/services/oauth/access_token';
private $oauthToken = null;
private $oauthTokenSecret = null;
private $tokenFile;
public function __construct($consumerKey, $consumerSecret)
{
$this->consumerKey = $consumerKey;
$this->consumerSecret = $consumerSecret;
$this->tokenFile = __DIR__ . '/../data/oauth_token.json';
// Load saved tokens if exist
$this->loadTokens();
}
/**
* Check if we have valid access tokens
*/
public function isAuthorized()
{
return !empty($this->oauthToken) && !empty($this->oauthTokenSecret);
}
/**
* Get stored OAuth token
*/
public function getOAuthToken()
{
return $this->oauthToken;
}
/**
* Get stored OAuth token secret
*/
public function getOAuthTokenSecret()
{
return $this->oauthTokenSecret;
}
/**
* Step 1: Get request token and return authorization URL
*/
public function getAuthorizationUrl($callbackUrl)
{
$params = [
'oauth_callback' => $callbackUrl,
'oauth_consumer_key' => $this->consumerKey,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_version' => '1.0',
];
$params['oauth_signature'] = $this->generateSignature('GET', $this->requestTokenUrl, $params);
$url = $this->requestTokenUrl . '?' . http_build_query($params);
$response = $this->httpRequest($url);
if (!$response) {
throw new Exception('Failed to get request token');
}
parse_str($response, $data);
if (!isset($data['oauth_token']) || !isset($data['oauth_token_secret'])) {
throw new Exception('Invalid request token response: ' . $response);
}
// Store request token temporarily (needed for step 2)
$_SESSION['flickr_request_token'] = $data['oauth_token'];
$_SESSION['flickr_request_token_secret'] = $data['oauth_token_secret'];
// Return URL for user to authorize
return $this->authorizeUrl . '?oauth_token=' . $data['oauth_token'] . '&perms=read';
}
/**
* Step 2: Exchange verifier for access token
*/
public function handleCallback($oauthToken, $oauthVerifier)
{
if (!isset($_SESSION['flickr_request_token_secret'])) {
throw new Exception('Request token secret not found in session');
}
$requestTokenSecret = $_SESSION['flickr_request_token_secret'];
$params = [
'oauth_consumer_key' => $this->consumerKey,
'oauth_token' => $oauthToken,
'oauth_verifier' => $oauthVerifier,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_version' => '1.0',
];
$params['oauth_signature'] = $this->generateSignature(
'GET',
$this->accessTokenUrl,
$params,
$requestTokenSecret
);
$url = $this->accessTokenUrl . '?' . http_build_query($params);
$response = $this->httpRequest($url);
if (!$response) {
throw new Exception('Failed to get access token');
}
parse_str($response, $data);
if (!isset($data['oauth_token']) || !isset($data['oauth_token_secret'])) {
throw new Exception('Invalid access token response: ' . $response);
}
// Save access tokens
$this->oauthToken = $data['oauth_token'];
$this->oauthTokenSecret = $data['oauth_token_secret'];
$this->saveTokens($data);
// Clean up session
unset($_SESSION['flickr_request_token']);
unset($_SESSION['flickr_request_token_secret']);
return [
'oauth_token' => $this->oauthToken,
'user_nsid' => $data['user_nsid'] ?? null,
'username' => $data['username'] ?? null,
'fullname' => $data['fullname'] ?? null,
];
}
/**
* Sign an API request with OAuth
*/
public function signRequest($method, $url, $params = [])
{
$oauthParams = [
'oauth_consumer_key' => $this->consumerKey,
'oauth_token' => $this->oauthToken,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_version' => '1.0',
];
$allParams = array_merge($params, $oauthParams);
$oauthParams['oauth_signature'] = $this->generateSignature(
$method,
$url,
$allParams,
$this->oauthTokenSecret
);
return $oauthParams;
}
/**
* Generate OAuth signature
*/
private function generateSignature($method, $url, $params, $tokenSecret = '')
{
ksort($params);
$paramString = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$baseString = strtoupper($method) . '&'
. rawurlencode($url) . '&'
. rawurlencode($paramString);
$signingKey = rawurlencode($this->consumerSecret) . '&' . rawurlencode($tokenSecret);
return base64_encode(hash_hmac('sha1', $baseString, $signingKey, true));
}
/**
* Generate random nonce
*/
private function generateNonce()
{
return md5(uniqid(mt_rand(), true));
}
/**
* Make HTTP request
*/
private function httpRequest($url)
{
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
return false;
}
return $response;
}
/**
* Save tokens to file
*/
private function saveTokens($data)
{
$dir = dirname($this->tokenFile);
if (!is_dir($dir)) {
mkdir($dir, 0700, true);
}
$tokenData = [
'oauth_token' => $data['oauth_token'],
'oauth_token_secret' => $data['oauth_token_secret'],
'user_nsid' => $data['user_nsid'] ?? null,
'username' => $data['username'] ?? null,
'created_at' => date('Y-m-d H:i:s'),
];
file_put_contents($this->tokenFile, json_encode($tokenData, JSON_PRETTY_PRINT));
chmod($this->tokenFile, 0600);
}
/**
* Load tokens from file
*/
private function loadTokens()
{
if (file_exists($this->tokenFile)) {
$data = json_decode(file_get_contents($this->tokenFile), true);
if ($data) {
$this->oauthToken = $data['oauth_token'] ?? null;
$this->oauthTokenSecret = $data['oauth_token_secret'] ?? null;
}
}
}
/**
* Clear saved tokens (logout)
*/
public function clearTokens()
{
$this->oauthToken = null;
$this->oauthTokenSecret = null;
if (file_exists($this->tokenFile)) {
unlink($this->tokenFile);
}
}
}