Tag Archive ดาวน์โหลด

Byphunsanit

Fetch API: Download

ที่นี้มาถึงการที่ใช้ fetch download file จาก server ซึ่งวิธีนี้ง่ายกว่าการใช้ jQuery ดึงไฟล์มามาก จากที่เคยเขียน jQuery ajax download file เอาไว้จะเห็นว่าวิธีนี้ง่ายกว่ามาก

เริ่มจากการที่โหลด download.js มาก่อน โดยใช้คำสั่ง npm i downloadjs
ไฟล์กลางที่ไว้ใช้ร่วมกัน

scripts.js

/*
pitt phunsanit
default fetch api options
version 1
*/
let fetchOptions = {
    "headers": {
        'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    "method": "post"
};

/*
pitt phunsanit
get file name from fetch api
version 1
*/
function fetchGetFilename(response) {
    let filename = '';
    let disposition = response.headers.get('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        let matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) {
            filename = matches[1].replace(/['"]/g, '');
        }
    }
    return filename;
}

/*
pitt phunsanit
get status from fetch api
version 1
*/
function fetchStatus(Response) {
    if (Response.status >= 200 && Response.status < 300) {
        return Promise.resolve(Response);
    } else {
        return Promise.reject(new Error(Response.status + ' : ' + Response.statusText));
    }
}

ตัวอย่างการใช้ fetch download file โดยใช้ downloadjs ช่วยให้ทำงานได้ทุกบราวเซอร์ (ยกเว้น IE ถ้าจะใช้กลับไปอ่าน Fetch API)

JavaScript/fetch.download.html
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

      <meta name="author" content="Pitt Phunsanit">
      <title>fetch: download</title>
   </head>
   <body>
      <script src="../node_modules/downloadjs/download.min.js"></script>
      <script src="../scripts.js"></script>
      <script>
fetchOptions.body = 'file=ISO 3166-1 two aplha COUNTRY codes (01102009).xls&token=HH89VOiirgXlCdEqDrFs';

fetch('http://localhost/snippets/PHP/download.php', fetchOptions)
    .then(fetchStatus)
    .then(
        function(response) {
            if (response.ok) {
                let fileName = fetchGetFilename(response);
                let mimeType = response.headers.get('Content-Type');

                response.blob().then(function(blob) {
                    download(blob, fileName, mimeType);
                });
            }
        }
    )
    .catch(function(error) {
        alert(error);
    });
      </script>

</body></html>

อ่านเพิ่มเติม

Byphunsanit

php: download ไฟล์จาก server

ตัวอย่าง code php ไว้ download ไฟล์จาก server

PHP/download.php
<?php
$fileDir = '../assets/';
$token = 'HH89VOiirgXlCdEqDrFs';

if ($_REQUEST['token'] != $token) {
    exit('bad token');
}

$file = $fileDir . $_REQUEST['file'];
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: ' . mime_content_type($file));
    header('Content-Disposition: attachment; filename="' . basename($file) . '"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));

    //readfile($file);
    echo file_get_contents($file);
} else {
    exit('file not found');
}

เพราะว่า ออกแบบให้สามารถโหลดไฟล์อะไรก็ได้จาก server เลยมีการใช้ token ช่วยในการตรวจสอบความปลอดภัยเล็กน้อย ของจริงต้องแก้ให้ตรวจ token ซับซ้อนกว่านี้เพื่อความปลอดภัย

Byphunsanit

curl: ดาวน์โหลดไฟล์

การใช้ curl ไป download file จากเซิร์ฟเวอร์อื่นๆ ไม่ได้ซับซ้อนเหมือนการอัพโหลดในตัวอย่าง curl: ส่งไฟล์ การทำงานค่อนข้างตรงไปตรงมาก คือ มีไฟล์ที่มี code curl ทำหน้าที่ request และมีไฟล์หรือโปรแกรมที่ทำหน้าที่จ่ายไฟล์ให้ โดยดัดแปลงให้แสดง error กลับมาในรูปแบบที่ง่ายกับการแสดง error ในฝั่งรีเควสท์

เพื่อความปลอดภัย จะมีการเขียนการตรวจสอบเล็กน้อย

  • จะส่ง token มาและทั้ง 2 ไฟล์จะต้องมีค่าเท่าๆกัน ในความเป็นจริง ควรจะมีการเขียนที่ดีกว่านี้ เช่น เปลี่ยน token ตามช่วงเวลา
  • ไม่ควรให้ร้องขอไฟล์โดยใช้ full path และเพื่อป้องกันการใช้ฝั่งรับในการ download ไฟล์อื่นๆ จึงต้องกำหนดโฟลเดอร์เริ่มต้นไว้ให้ดาวน์โหลดไฟล์ในโฟลเดอร์ที่กำหนดไว้เท่านั้น
  • <?php
    header('Cache-Control: no-cache, no-store, must-revalidate');
    header('Expires: 0');
    header('Pragma: no-cache');
    
    $post = [
        'file' => 'test.docx',
        'token' => $token,
    ];
    $token = 'HH89VOiirgXlCdEqDrFs';
    $url = 'http://localhost/snippets/PHP/download.php';
    
    $ch = curl_init();
    
    curl_setopt_array($ch, [
        CURLOPT_ENCODING => 'UTF-8',
        CURLOPT_FRESH_CONNECT => true,
        CURLOPT_POST => 1,
        CURLOPT_POSTFIELDS => http_build_query($post),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_URL => $url,
    ]);
    
    $result = curl_exec($ch);
    
    switch ($result) {
        case 'bad token':{
                curl_close($ch);
                exit('check token in ' . $url);
            }break;
    
        case 'file not found':{
                curl_close($ch);
                exit('file not found in target server.');
            }break;
    
        default:{
                header('Content-Disposition: attachment; filename="' . $post['file']);
                echo $result;
            }
    }
    curl_close($ch);

    <?php
    $fileDir = '../assets/';
    $token = 'HH89VOiirgXlCdEqDrFs';
    
    if ($_REQUEST['token'] != $token) {
        exit('bad token');
    }
    
    $file = $fileDir . $_REQUEST['file'];
    if (file_exists($file)) {
        header('Content-Description: File Transfer');
        header('Content-Type: ' . mime_content_type($file));
        header('Content-Disposition: attachment; filename="' . basename($file) . '"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($file));
    
        //readfile($file);
        echo file_get_contents($file);
    } else {
        exit('file not found');
    }
    

Byphunsanit

jQuery ajax download file

มีวิธีที่ง่ายกว่า Fetch API: Download

งานที่ทำอยู่วันนี้ ต้องส่งข้อมูลไปให้อีกไฟล์เพื่อสร้างไฟล์ excel ให้ดาวน์โหลด แต่เพราะว่าจำเป็นต้องส่งรายการ ที่เลือกไปให้ด้วย บางครั้งมันยาวเกินกว่าที่จะส่งไปแบบ GET ทำให้ต้องส่งแบบ post และไม่อยากจะใช้วิธี submit form ไปอีกหน้าเพราะว่าหน้านี้เป็นแบบใช้ ajax ทั้งหมด ปัญหาคือ jquery ajax มันไม่รองรับการ download file จริงๆ ถ้าจะทำก็ทำได้ แต่เขียนยุ่งยากมาก แต่ก็มีคนเขียน jquery.fileDownload ทำให้ทำได้ง่ายๆมากๆ แค่ใส่ url ไปแค่นั้นเอง

<!doctype html>
<html>
   <head>
      <meta charset="utf-8">
      <title>jquery.fileDownload</title>
      <link href="vendor/components/jqueryui/themes/base/jquery-ui.min.css" rel="stylesheet" type="text/css" />
   </head>
   <body>
      <button id="downloadBtn" type="button">Download with dialog</button>
      <hr>
      <button id="downloadBtn1" type="button">Download without dialog</button>
      <hr>
      <form action="PHPExcel_writer_styles_border.php" id="formA" method="post">
         <label>Search :
         <input name="search" type="text"></label>
         <button type="submit">Download with form</button>
      </form>
      <script src="vendor/components/jquery/jquery.min.js"></script>
      <script src="vendor/components/jqueryui/jquery-ui.min.js"></script>
      <script src="vendor/johnculviner/jquery.fileDownload/src/Scripts/jquery.fileDownload.js"></script>
      <script>
         $(function() {

             $('#downloadBtn').click(function(event) {
                 event.preventDefault();

                  $.fileDownload('PHPExcel_writer_styles_border.php', {
                     failMessageHtml: "There was a problem generating your report, please try again.",
                     preparingMessageHtml: "We are preparing your report, please wait...",
                 });

             });

             $('#downloadBtn1').click(function(event) {
                 event.preventDefault();

                  $.fileDownload('PHPExcel_writer_styles_border.php');

             });

             $('#formA').submit(function(event) {
                 event.preventDefault();

                 $.fileDownload($(this).prop('action'), {
                     data: $(this).serialize(),
                     failMessageHtml: "There was a problem generating your report, please try again.",
                     httpMethod: "POST",
                     preparingMessageHtml: "We are preparing your report, please wait...",
                 });

             });

         });
      </script>
   </body>
</html>

Byphunsanit

ดูบิตทอเร้นที่กำลังโหลดใน synology

ตัว nas ของ synology จะมี package ไว้สำหรับดาวน์โหลดชื่อ Download Station แต่ข้อเสียของมันคือในตอนที่ download อยู่จะไม่สามารถดูได้ว่า torrent ที่โหลดอยู่นะ มันน่าจะโหลดต่อ หรือเป็นแค่งานกากๆ ที่สมควรที่จะลบทิ้งไม่ต้องโหลดให้เปลืองเรโต

การที่ทำให้ดูงานที่ยังไม่เสร็จนี้ต้องใช้พลังภายในมากหน่อยแต่ไม่ยากเกินความพยามครับ

  1. สร้าง user ใหม่ ไปที่ Control Panel > User > เลือก Create สร้าง user ใหม่โดย User group ให้ติ๊ก administrators ด้วยและ Permissions ให้เลือก Read/Write ทั้งหมดไปเลย
  2. ด้านบนขวามือคลิก Advance Mode > Terminal & SNMP > ติ๊ก Enable SSH service > Apply
  3. สร้างโพล์เดอร์ใหม่ โดยใช้ File Station เลือก Create > Create New Share Folder > กรอก Name ผมใช้ชื่อ bit แล้วกด ok
  4. ทดลองโดยไปที่ เมนูขอเครื่องเรา คลิก run พิมพ์ //ip ของ synology/ แล้วเอ็นเทอร์ เช่น ip คือ 192.168.1.69 ก็พิมพ์ //192.168.1.69/ ถ้ามีกล่องใหม่เปิดขึ้นมา ก็กรอก username กับ pass ที่ใช้ login synology
  5. สร้างโฟล์เดอร์ใหม่เช่น 2 downloads
  6. โหลด PuTTY มาจาก http://www.putty.org แล้ว dubble click เปิดโปรแกรมขึ้นมาเลย ช่อง Host Name (or IP address) ใส่ ip ของ Synology ลงไป ถ้าไมรู้ก็เลขที่อยู่ด้านบนหน้าจัดการของ Synology ที่เป็น 192.168.1.69:8090/webman/index.cgi แต่ใส่แค่ 192.168.1.69 เข้าไปก็พอ กด open มันจะกลายเป็นหน้าตาดำๆ ไม่น่าคบ ไม่ต้องกลัว
    • มันจะถาม Login as :
    • พิมพ์ user ที่สร้างใหม่ กดเอ็นเทอร์
    • มันจะถามกลับ
    • [email protected]’s password:
    • ใส่ password ตัวเดียวกับที่ user ที่สร้างใหม่
    • รอให้มันตอบซักครู่ พอนิ่งเห็น ชื่อเครื่องของเรา ประมาณ Synology> นิ่งๆ แล้วก็พิมพ์
      sudo -i
      mount --bind /volume1/@download "/volume1/bit/2 downloads"
      

      (ตัวเล็กตัวใหญ่ต้องตรงกัน) แล้วเอ็นเตอร์ ถ้ามันกลับมาถาม Synology> ให้ปิด putty ไปได้เลย

  7. อย่าลืมดู Permission ของทุก folder ที่ใช้ว่า DownloadStation มีสิทธิอ่านเขียน อยู่มั๋ย

อธิบายคือสั่งให้โฟลเดอร์ที่เก็บงานที่ยังดาวน์โหลดไม่เสร็จที่เก็บไว้ที่ /volume1/@download จะถูก mount คือทำให้ folder /volume1/bit/2 downloads แสดงไฟล์ข้างในเหมือน /volume1/@download ทุกอย่าง ถ้าใช้ชื่ออื่นก็เปลี่ยนไปตามชื่อที่ตั้ง

ตอนนี้เมือเรียก //ip ของ synology/bit/2 downloads จะเห็นไฟล์ที่กำลังโหลดอยู่ บางไฟล์เปิดไม่ได้ไม่ต้องตกใจเพราะมันยังโหลดไม่เสร็จ แต่อย่างน้อยก็ดูได้ว่างานที่จะได้ไปต่อมั๋ย

ดู mount ทั้งหมดโดยใช้คำสั่ง

sudo -i
mount

ถ้าต้องการเอาความเชื่อมโยงนี้แแกก็ใช้คำสั่ง

sudo -i
umount "/volume1/bit/2 downloads"