Menu

Cách làm api phạt nguội bằng laravel

Programming Knowledge | Aug 26, 2024 762
#Source #frontend developer #backend develop

Trong những năm gần đây, vấn đề phạt nguội giao thông đang được rất nhiều tài xế quan tâm. Việc tra cứu thông tin vi phạm không chỉ giúp người dùng nắm rõ tình trạng phương tiện, mà còn tránh được những rắc rối khi đi đăng kiểm hoặc lưu thông trên đường. Thay vì phải truy cập thủ công vào website của CSGT, chúng ta hoàn toàn có thể xây dựng một API tra cứu phạt nguội để tích hợp trực tiếp vào hệ thống quản lý, ứng dụng di động hay website của mình. 

Trong bài viết này, tôi sẽ hướng dẫn bạn cách xây dựng một API check phạt nguội đơn giản bằng PHP Laravel như trang "Check Phạt Nguội", bao gồm các bước từ cấu hình dự án, xử lý request/response đến hiển thị kết quả. Với cách làm này, bạn có thể dễ dàng tự động hóa việc tra cứu, tiết kiệm thời gian và tăng tính tiện lợi cho người dùng.


<?php namespace Dev\KOMA\Services;

class PhatNguoiService {
    private string $url = "https://www.csgt.vn/tra-cuu-phuong-tien-vi-pham.html";
    private string $captchaFile;
    private string $search_url = "https://www.csgt.vn/?mod=contact&task=tracuu_post&ajax";
    private ?string $sessionId = null; // giữ PHPSESSID

    public function __construct(string $storageDir = __DIR__) {
        $this->captchaFile = $storageDir . "/captcha_" . uniqid() . ".png";
    }

    /**
     * @throws \RuntimeException
     * @return array
     */
    public function run($bienKS, $xe): array {
        try {
            // 1. Get main page HTML and sessionId
            $html = $this->fetchMainPage($this->url);

            // 2. Get captcha image URL
            $imgUrl = $this->getCaptchaUrl($html);

            // 3. Download captcha
            $this->downloadCaptcha($imgUrl);

            // 4. Send captcha to get ID
            $responseCaptcha = $this->sendCaptcha();
            $captcha_id = $this->cutResponse($responseCaptcha);

            // 5. Get captcha result
            $captchaText = $this->getCaptchaResult($captcha_id);
            $captcha = $this->cutResponse($captchaText);

            // 6. Submit form
            $response = $this->submitForm($bienKS, $xe, $captcha);

            if ($response === '404') {
                throw new \RuntimeException('Không tìm thấy kết quả');
            }

            $result = json_decode($response, true);

            if (!is_array($result)) {
                throw new \RuntimeException('Kết quả không phải là JSON hợp lệ');
            }

            if (!isset($result['success'])) {
                throw new \RuntimeException('Thiếu trường success trong kết quả');
            }

            if ($result['success'] !== "true") {
                throw new \RuntimeException('Không có kết quả hợp lệ');
            }

            $html = $this->fetchMainPage($result['href'], false);
            $data = $this->parseBodyPrint($html);

            // Clean up captcha file after processing
            if (file_exists($this->captchaFile)) {
                unlink($this->captchaFile);
            }

            return $data;
        } catch (\Exception $e) {
            // Clean up file even if there's an error
            if (file_exists($this->captchaFile)) {
                unlink($this->captchaFile);
            }
            throw $e; // Re-throw the exception after cleanup
        }
    }

    private function parseBodyPrint(string $html): array {
        $doc = new \DOMDocument();
        libxml_use_internal_errors(true);
        $doc->loadHTML($html);
        libxml_clear_errors();

        $xpath = new \DOMXPath($doc);

        // tìm div có id=bodyPrint123
        $target = $xpath->query("//div[@id='bodyPrint123']")->item(0);
        if (!$target) {
            return ["error" => "Không tìm thấy bodyPrint123"];
        }

        $data = [];
        $rows = $xpath->query(".//div[contains(concat(' ', normalize-space(@class), ' '), ' form-group ')]", $target);
        foreach ($rows as $row) {
            $labelNode = $xpath->query(".//label//span", $row)->item(0);
            $valueNode = $xpath->query(".//div[contains(@class,'col-md-9')]", $row)->item(0);

            if ($labelNode && $valueNode) {
                $label = trim($labelNode->textContent);
                $value = trim($valueNode->textContent);
                $data[$label] = $value;
            } else {
                // những group không có label mà chỉ có text (ví dụ địa chỉ, đơn vị xử lý)
                $text = trim($row->textContent);
                if ($text !== '') {
                    $data[] = $text;
                }
            }
        }

        return $data;
    }

    private function fetchMainPage($url, $flag = true) {
        $ch = curl_init($url);

        $options = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HEADER => true, // để tách header/body khi flag = true
            CURLOPT_USERAGENT => "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
        ];

        if (!$flag && $this->sessionId) {
            // Khi flag = false thì gửi kèm sessionId
            $options[CURLOPT_HTTPHEADER] = [
                "Cookie: PHPSESSID={$this->sessionId}"
            ];
            // Lúc này không cần tách header ra nữa
            $options[CURLOPT_HEADER] = false;
        }

        curl_setopt_array($ch, $options);

        $response = curl_exec($ch);
        curl_close($ch);

        if ($flag) {
            [$header, $body] = explode("\r\n\r\n", $response, 2);
            if (preg_match('/PHPSESSID=([^;]+)/', $header, $m)) {
                $this->sessionId = $m[1];
            }
            return $body;
        }

        return $response;
    }

    private function submitForm(string $bienSo, string $loaiXe, string $captchaText): string {
        $postFields = [
            'BienKS' => $bienSo,
            'Xe' => $loaiXe,
            'captcha'  => $captchaText,
            'ipClient' => '9.9.9.91',
            'cUrl' => '1'
        ];
        $data = http_build_query($postFields);
        // Dùng PHPSESSID lấy từ fetchMainPage
        $cookie = $this->sessionId ? "PHPSESSID={$this->sessionId}" : "";
        $ch = curl_init($this->search_url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $data,
            CURLOPT_HTTPHEADER => [
                "Content-Type: application/x-www-form-urlencoded; charset=UTF-8",
                "Referer: " . $this->url,
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
                "X-Requested-With: XMLHttpRequest",
                "Accept: */*",
                "Cookie: $cookie",
            ],
        ]);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }

    private function getCaptchaUrl(string $html): string {
        $dom = new \DOMDocument();
        libxml_use_internal_errors(true);
        $dom->loadHTML($html);
        libxml_clear_errors();
        $xpath = new \DOMXPath($dom);
        $nodeList = $xpath->query("//img[@id='imgCaptcha']");

        if ($nodeList === false || $nodeList->length === 0) {
            throw new \RuntimeException("Không tìm thấy captcha trong HTML");
        }

        /** @var \DOMElement $imgNode */
        $imgNode = $nodeList->item(0);
        $imgSrc = $imgNode->getAttribute("src");
        $parsedUrl = parse_url($this->url);
        $base = $parsedUrl['scheme'] . "://" . $parsedUrl['host'];
        return (strpos($imgSrc, "http") !== 0)
            ? rtrim($base, "/") . "/" . ltrim($imgSrc, "/")
            : $imgSrc;
    }

    private function downloadCaptcha(string $imgUrl): void {
        $ch = curl_init($imgUrl);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_COOKIE => "PHPSESSID={$this->sessionId}" // tải captcha cũng phải kèm session
        ]);
        $imgData = curl_exec($ch);
        curl_close($ch);
        file_put_contents($this->captchaFile, $imgData);
    }

    private function sendCaptcha(): string {
        $ch = curl_init("https://captcha.lapro.vn/in.php");
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => [
                "file" => new \CURLFile($this->captchaFile),
            ],
        ]);
        $responseCaptcha = curl_exec($ch);
        curl_close($ch);

        return $responseCaptcha;
    }

    private function cutResponse(string $responseCaptcha): string {
        if (strpos($responseCaptcha, "OK|") === 0) {
            return explode("|", $responseCaptcha)[1];
        }
        die("Lỗi gửi captcha: $responseCaptcha<br>");
    }

    private function getCaptchaResult(string $captcha_id): string {
        for ($i = 0; $i < 10; $i++) {
            sleep(3);
            $ch = curl_init("https://captcha.lapro.vn/res.php?id=" . trim($captcha_id));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $result = curl_exec($ch);
            curl_close($ch);

            if ($result && $result !== "NOT_READY") {
                return $result;
            }
        }
        return "NOT_READY";
    }
}

>>>Xem kết quả tại: Kiểm tra phạt nguội

Chia sẻ bài viết

Tính Thần Số Học Tại Đây

Khám phá bản thân qua các con số từ tên và ngày sinh của bạn

Bình luận

Chia sẻ cảm nghĩ của bạn về bài viết này.

Chưa có bình luận nào. Hãy là người đầu tiên!

Danh sách các bài viết mới nhất 112 bài viết

Danh mục bài viết

Kiến thức lập trình

Khám phá kiến thức lập trình tại Khaizinam Site: hướng dẫn, mẹo, ví dụ thực tế và tài nguyên giúp bạn nâng cao kỹ năng lập trình hiệu quả.

Mã nguồn lập trình

Chia sẻ các mã nguồn hữu ích cho mọi người sử dụng.

Thế giới

Tin tức vòng quanh thế giới

Công nghệ

Enim sit aut facere ipsum dolores corrupti at reprehenderit. Ea illum doloribus et tempore maiores iure. Laboriosam iste enim non expedita minima libero.

Xã hội

Tin tức xã hội, biến động 24h qua trên toàn cầu

Manga Anime

Tin tức về anime, manga được cập nhật mới nhất

Thể thao

Tin tức thể thao toàn cầu được cập nhật hàng ngày

Giải trí

Tin tức giải trí toàn thế giới được cập nhật mới nhất,

Dịch vụ

Khám phá các bài viết trong danh mục này

Làng hải tặc FNS

Game làng hải tặc của Funnysoft, sự kết hợp hoàn hảo giữa HSO, HTTH của teamobi

Pháp luật

Khám phá các bài viết trong danh mục này

Ngoài lề

Khám phá các bài viết trong danh mục này

Thần số học

Khám phá các bài viết trong danh mục này

Tiếng Việt flag Tiếng Việt

Tính Thần Số Học

Khám phá bản thân qua các con số

Tìm Hiểu