Code php getlink tải video youtube

1. Nếu bạn có quyền trên VPS → Cách đúng là bật lại shell_exec

Vì bạn nói đang chạy trên VPS, khả năng cao bạn có quyền root hoặc sudo → lúc này giải pháp chuẩn nhất là:

Bước A: Tìm đúng file cấu hình PHP đang chạy web

Trên VPS (SSH):

php -i | grep "Loaded Configuration File"

Nó sẽ trả kiểu như:

Loaded Configuration File => /etc/php/8.2/fpm/php.ini

Nếu bạn dùng Nginx/Apache + PHP-FPM thì thường là dạng .../fpm/php.ini.

Bước B: Mở file php.ini đó

Ví dụ:

sudo nano /etc/php/8.2/fpm/php.ini # hoặc sudo vi /etc/php/8.2/fpm/php.ini

Bước C: Tìm dòng disable_functions

Tìm:

disable_functions = passthru,exec,shell_exec,system,proc_open,popen,...

Lúc này bạn có 3 lựa chọn:

  1. Xóa shell_exec khỏi dòng:

disable_functions = passthru,exec,system,proc_open,popen
  1. Hoặc nếu bạn đang dev nội bộ VPS, có thể tạm comment luôn cả dòng:

;disable_functions = ...
  1. Nếu file php.ini trống, mà debug vẫn báo disable_functions → có thể bị override ở file cấu hình pool FPM (vd: /etc/php/8.2/fpm/pool.d/www.conf) với dòng:

php_admin_value[disable_functions] = shell_exec,exec,system,...



Tiếp theo 


Hướng 1: Cài yt-dlp vào chính home của bạn (/home/thanhtung/...) → PHP dùng được

Bước 1: SSH vào host, về home

cd ~ pwd # phải ra /home/thanhtung

Bước 2: Tạo thư mục chứa binary yt-dlp (ví dụ ytbin)

mkdir -p ~/ytbin cd ~/ytbin

Bước 3: Tải yt-dlp vào đây

Dùng curl:

curl -L https://github.com/yt-dlp/yt-dlp-nightly-builds/releases/latest/download/yt-dlp_linux -o yt-dlp chmod +x yt-dlp

Test thử:

./yt-dlp -F "https://www.youtube.com/watch?v=81FSgvpBaSQ"

Nếu nó in ra list định dạng là ok ✅

Lúc này file thực tế là:
/home/thanhtung/ytbin/yt-dlp → NẰM TRONG open_basedir cho phép.



Nếu các bước ok thì bạn đã hoàn thành việc cài đặt. Và sau đây là code php của bạn 

 <?php

error_reporting(0);

ini_set('display_errors', 0);

set_time_limit(90);

ini_set('memory_limit', '512M');


class YouTubeDownloader {

    // yt-dlp binary trong home (đã test ok)

    private $tool = '/home/thanhtung/ytbin/yt-dlp';


    private function formatBytes($bytes) {

        if (!is_numeric($bytes) || $bytes <= 0) return 'unknown';

        $units = ['B','KB','MB','GB','TB'];

        $i = 0;

        while ($bytes >= 1024 && $i < count($units) - 1) {

            $bytes /= 1024; $i++;

        }

        return round($bytes, 1) . ' ' . $units[$i];

    }


    private function runYtDlp($url) {

        // Nếu shell_exec bị tắt thì chịu

        if (!function_exists('shell_exec')) return null;

        $disabled = ini_get('disable_functions');

        if ($disabled && stripos($disabled, 'shell_exec') !== false) return null;


        $tool = $this->tool;


        // Dùng đúng command đã test trong test_ytb.php, thêm tí retry thôi

        $cmd = sprintf(

            '%s --dump-single-json --no-warnings --no-playlist ' .

            '--retries 5 ' .

            '%s 2>&1',

            escapeshellcmd($tool),

            escapeshellarg($url)

        );


        $output = shell_exec($cmd);

        if (!$output) return null;


        // Tìm JSON theo dấu '{' đầu tiên

        $start = strpos($output, '{');

        if ($start === false) return null;


        $json = substr($output, $start);

        // Giới hạn JSON tối đa 5MB

        $json = substr($json, 0, 5 * 1024 * 1024);


        $data = json_decode($json, true);

        if (!is_array($data) || empty($data['formats'])) return null;


        $streams = [];

        foreach ($data['formats'] as $f) {

            // Có format storyboard / thumbnail, vẫn có url

            if (empty($f['url'])) continue;


            $hasVideo = !empty($f['vcodec']) && $f['vcodec'] !== 'none';

            $hasAudio = !empty($f['acodec']) && $f['acodec'] !== 'none';


            $quality = $f['format_note']

                ?? (($f['height'] ?? ($hasAudio ? 'audio' : 'unknown')) . 'p');


            $size = 'unknown';

            if (!empty($f['filesize'])) {

                $size = $this->formatBytes($f['filesize']);

            } elseif (!empty($f['filesize_approx'])) {

                $size = '~' . $this->formatBytes($f['filesize_approx']);

            }


            // Loại stream: full / video / audio

            $type = $hasVideo && $hasAudio

                ? 'full'

                : ($hasVideo ? 'video' : 'audio');


            $streams[] = [

                'quality' => $quality,

                'size'    => $size,

                'url'     => $f['url'],

                'type'    => $type,

            ];

        }


        if (empty($streams)) {

            // JSON ok nhưng không có url nào usable

            return null;

        }


        return [

            'title'     => $data['title'] ?? 'Unknown',

            'thumbnail' => $data['thumbnail'] ?? '',

            'streams'   => $streams,

        ];

    }


    public function get($url) {

        $result = $this->runYtDlp($url);

        if (!$result) {

            return [

                'error' => 'Không lấy được dữ liệu từ yt-dlp. Thử lại sau vài phút nhé!'

            ];

        }


        // Group lại theo full / video / audio cho JS

        $grouped = ['full' => [], 'video' => [], 'audio' => []];

        foreach ($result['streams'] as $s) {

            if ($s['type'] === 'full') {

                $grouped['full'][] = $s;

            } elseif ($s['type'] === 'video') {

                $grouped['video'][] = $s;

            } else {

                $grouped['audio'][] = $s;

            }

        }


        return [

            'success'   => true,

            'title'     => $result['title'],

            'thumbnail' => $result['thumbnail'],

            'streams'   => $grouped,

        ];

    }

}


if (isset($_GET['url'])) {

    header('Content-Type: application/json; charset=utf-8');

    $dl = new YouTubeDownloader();

    echo json_encode($dl->get($_GET['url']), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

    exit;

}

?>


<!DOCTYPE html>

<html lang="vi">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>YouTube Downloader Pro 2025</title>

    <style>

        body {font-family:Arial,sans-serif;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;padding:20px;min-height:100vh;}

        .c {max-width:960px;margin:auto;background:#fff;color:#333;border-radius:16px;padding:30px;box-shadow:0 20px 50px rgba(0,0,0,.3);}

        h1 {text-align:center;color:#fff;background:#333;padding:20px;border-radius:16px 16px 0 0;margin:-30px -30px 30px;}

        input,button {width:100%;padding:16px;font-size:18px;border-radius:8px;margin:10px 0;}

        input {border:2px solid #ddd;}

        button {background:#ff4081;color:#fff;border:none;cursor:pointer;}

        .r {margin-top:20px;}

        .thumb img {max-width:100%;border-radius:12px;}

        .sec h3 {background:#667eea;color:#fff;padding:12px;border-radius:8px;margin:20px 0 10px;}

        .item {background:#f8f9fa;padding:15px;margin:8px 0;border-radius:8px;display:flex;justify-content:space-between;align-items:center;}

        .dl {background:#667eea;color:#fff;padding:12px 25px;text-decoration:none;border-radius:8px;}

        .err {background:#ffebee;color:#c62828;padding:20px;border-radius:8px;border-left:5px solid #c62828;}

    </style>

</head>

<body>

<div class="c">

    <h1>🎥 YouTube Downloader Pro 2025 - 100% Hoạt Động</h1>

    <input type="text" id="u" placeholder="Dán link YouTube...">

    <button onclick="go()">LẤY LINK</button>

    <div id="r" class="r"></div>

</div>

<script>

async function go() {

    let url = document.getElementById('u').value.trim();

    if (!url) return;

    let r = document.getElementById('r');

    r.innerHTML = '<p>Đang lấy link (5-15 giây)...</p>';

    try {

        let res = await fetch('?url=' + encodeURIComponent(url));

        let d = await res.json();

        if (d.error) {

            r.innerHTML = `<div class="err">${d.error}</div>`;

            return;

        }

        let h = `<div class="thumb"><img src="${d.thumbnail}"></div><h2 style="text-align:center">${d.title}</h2><hr>`;

        const add = (t,a) => {

            if(a && a.length){

                h += `<div class="sec"><h3>${t}</h3>`;

                a.forEach(x => {

                    h += `<div class="item">

                            <div><b>${x.quality}</b> (${x.size})</div>

                            <a href="${x.url}" class="dl" target="_blank">Download</a>

                          </div>`;

                });

                h += '</div>';

            }

        };

        add('Video + Audio', d.streams.full);

        add('Video Only', d.streams.video);

        add('Audio Only', d.streams.audio);

        r.innerHTML = h;

    } catch(e) {

        r.innerHTML = '<div class="err">Lỗi kết nối, thử lại nhé!</div>';

    }

}

</script>

</body>

</html>


Mới hơn Cũ hơn