PHP - Aes 加密上傳檔案

手把手 PHP 針對上傳檔案做 AES 加解密教學。

各位看倌,若是對 Aes 不太了解可以看這篇呦。

事前準備

需要各位看倌,請先幫我準備好 PHP 執行環境並建立同下圖的資料結構。

圖1

  • boss_o.jpeg 是一張由 Google 上抓取的圖片,作為範例檔案使用。
  • decode 放置解密後資料位置。
  • encrypt 放置加密後資料位置。
  • index.php 主程式,實作程式內部邏輯。

來點簡單的檔案上傳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
# 檔案上傳邏輯
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
$file = $_FILES['file']['tmp_name'];

# 檔案位置
$dest = 'encrypt/' . $_FILES['file']['name'];

# 將檔案移至指定位置
move_uploaded_file($file, $dest);

echo '上傳成功' . '</br>';
}
?>


<form method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file" />
<button>Submit</button>
</form>

只是一個簡單的檔案上傳邏輯,確保上傳檔案有成功放至資料夾 encrypt 內。

將上傳的檔案做加密的動作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
# 加密
function encrypt($key, $payload)
{
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}

# 寫入檔案
function setFile($msg, $dest)
{
//取出目錄路徑中目錄(不包括後面的檔案)
$dir_name = dirname($dest);

//如果目錄不存在就建立
if(!file_exists($dir_name)) {
mkdir(iconv("UTF-8", "GBK", $dir_name), 0777, true);
}

//開啟檔案資源通道,不存在則自動建立
$fp = fopen($dest, "w");

//寫入檔案
fwrite($fp, $msg);

//關閉資源通道
fclose($fp);
}

# 檔案上傳邏輯
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
$file = $_FILES['file']['tmp_name'];

$dest = 'encrypt/' . $_FILES['file']['name'];
$e = encrypt('testKey', file_get_contents($file));
setFile($e, $dest);

echo '上傳成功' . '</br>';
}
?>


<form method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file" />
<button>Submit</button>
</form>

此處將上傳的檔案內容取出做 AES 加密的行為,再將加密資料存回檔案

  • 透過 openssl_encrypt 加密內部資料,再由 base64_encode 將加密資料進行編碼以便儲存。
  • 此處筆者將 iv 值放置加密資料後面,方便解密。
  • setFile 是簡單的建立檔案並寫入內容邏輯。

將加密過的檔案做解密的動作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
# 解密
function decode($key, $garble)
{
list($encrypted_data, $iv) = explode('::', base64_decode($garble), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
}

# 寫入檔案
function setFile($msg, $dest)
{
//取出目錄路徑中目錄(不包括後面的檔案)
$dir_name = dirname($dest);

//如果目錄不存在就建立
if(!file_exists($dir_name)) {
mkdir(iconv("UTF-8", "GBK", $dir_name), 0777, true);
}

//開啟檔案資源通道,不存在則自動建立
$fp = fopen($dest, "w");

//寫入檔案
fwrite($fp, $msg);

//關閉資源通道
fclose($fp);
}

# 檔案上傳邏輯
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
$file = $_FILES['file']['tmp_name'];

$dest = 'decode/' . $_FILES['file']['name'];
$d = decode('testKey', file_get_contents($file));
setFile($d, $dest);

echo '上傳成功' . '</br>';
}
?>


<form method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file" />
<button>Submit</button>
</form>

上傳加密後的檔案,並透過 base64_decodeopenssl_decrypt 逆向將檔案解密出來。若正確解密的話能在資料夾 decode 內看到解密後的檔案。

  • 注意加密及解密時的 Key 要是一至的。
  • 由於 iv 值 被存於加密後檔案後面,實作上只要管控好 Key 就好。

後話

  • 由於 file_get_contents 是將檔案內容全部存於記憶體內,所以要注意檔案大小及 PHP 開放記憶體是否充足。

  • 加解密 keyiv 數值保管,可由看倌們自行決定。

    上述為普通的加解密邏輯實作及介紹,懶人包可直接抓取 CODE

Author

LinYoYo

Posted on

2021-10-08

Updated on

2022-01-19

Licensed under