action URL、欄位名(username/password/csrf_token)、請求方式(POST)。Set-Cookie(Session ID)。注意:Snoopy 早已停止維護,PHP 7/8 相容性差,僅供舊專案參考,新專案請用 cURL 或 Guzzle。
<?php
require 'Snoopy.class.php';
$snoopy = new Snoopy();
$snoopy->agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36';
$snoopy->referer = 'https://target.com/login';
$snoopy->cookies['PHPSESSID'] = 'known_session_if_any'; // 可預設
$loginUrl = 'https://target.com/login_check';
$postData = [
'username' => 'your_account',
'password' => 'your_password',
'_token' => 'csrf_token_from_login_page', // 需先 GET 登入頁解析
];
if ($snoopy->submit($loginUrl, $postData)) {
// 登入成功,Cookie 已自動儲存在 $snoopy->cookies
$snoopy->fetch('https://target.com/user/dashboard');
echo $snoopy->results;
} else {
echo '登入失敗: ' . $snoopy->error;
}
?>
<?php
class LoginSimulator {
private $ch;
private $cookieFile;
private $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36';
public function __construct(string $cookieDir = '/tmp/cookies') {
if (!is_dir($cookieDir)) @mkdir($cookieDir, 0755, true);
$this->cookieFile = $cookieDir . '/cookies_' . md5($_SERVER['HTTP_HOST'] ?? 'default') . '.txt';
$this->ch = curl_init();
curl_setopt_array($this->ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_COOKIEJAR => $this->cookieFile, // 儲存 Cookie
CURLOPT_COOKIEFILE => $this->cookieFile, // 讀取 Cookie
CURLOPT_USERAGENT => $this->userAgent,
CURLOPT_SSL_VERIFYPEER => false, // 僅開發測試
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
]);
}
// 取得登入頁面,解析 CSRF Token
public function getCsrfToken(string $loginPageUrl, string $tokenField = '_token'): ?string {
curl_setopt($this->ch, CURLOPT_URL, $loginPageUrl);
curl_setopt($this->ch, CURLOPT_POST, false);
$html = curl_exec($this->ch);
if ($html === false) return null;
// 簡單正則提取
if (preg_match('/]+name=["\']' . preg_quote($tokenField) . '["\'][^>]+value=["\']([^"\']+)["\']/i', $html, $m)) {
return $m[1];
}
// 或用 DOMDocument 更穩健
return null;
}
// 執行登入
public function login(string $loginUrl, array $credentials): bool {
$postFields = http_build_query($credentials);
curl_setopt($this->ch, CURLOPT_URL, $loginUrl);
curl_setopt($this->ch, CURLOPT_POST, true);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $postFields);
curl_setopt($this->ch, CURLOPT_REFERER, $loginUrl);
$response = curl_exec($this->ch);
if ($response === false) {
error_log('cURL error: ' . curl_error($this->ch));
return false;
}
$httpCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
// 判斷登入成功:302 導向、或回應包含特定文字、或 Cookie 中出現 session
return $httpCode === 302 || stripos($response, 'logout') !== false || stripos($response, 'dashboard') !== false;
}
// 登入後存取受保護頁面
public function get(string $url): ?string {
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLOPT_POST, false);
return curl_exec($this->ch);
}
public function post(string $url, array $data): ?string {
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLOPT_POST, true);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, http_build_query($data));
return curl_exec($this->ch);
}
public function __destruct() {
curl_close($this->ch);
}
}
// 使用範例
$sim = new LoginSimulator();
$token = $sim->getCsrfToken('https://target.com/login');
if ($token) {
$ok = $sim->login('https://target.com/login_check', [
'username' => 'account',
'password' => 'pass',
'_token' => $token,
]);
if ($ok) {
echo $sim->get('https://target.com/user/profile');
} else {
echo '登入失敗';
}
} else {
echo '無法取得 CSRF Token';
}
?>
| 挑戰 | 解決方案 |
|---|---|
| 密碼前端加密 (RSA/AES) | 逆向分析 JS 加密邏輯,用 PHP 實現同樣加密(phpseclib、openssl_encrypt) |
| 動態 Token/簽名 | 模擬 JS 算法生成,或用 Headless Chrome (Puppeteer/PHP-WebDriver) |
| 驗證碼 | OCR 識別 (Tesseract)、打碼平台、或人工介入 |
| 雙因子認證 (2FA) | TOTP 算法生成碼 (bacon/bacon-qr-code) |
| 完整 SPA/JS 渲染 | 改用 Puppeteer (Node) 或 PHP-WebDriver 驅動真實瀏覽器 |
User-Agent、Accept-Language、RefererSet-Cookie 的 HttpOnly、Secure、SameSite 屬性robots.txt 及服務條款。掌握 cURL 完整流程、Cookie 管理、CSRF 處理、錯誤重試,是 PHP 開發者進行系統整合與自動化的核心技能。