找回密码
 快速注册
搜索
查看: 116|回复: 12

[php]备份论坛附件

[复制链接]

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

hbghlyj 发表于 2022-5-8 04:25 |阅读模式
本帖最后由 hbghlyj 于 2024-3-31 12:40 编辑 以下是Kuing和我共同想出来的办法:把这三个文件放在同一个目录下:
$type index.php (2.52 KB, 下载次数: 0)
$type attachment.php (296 Bytes, 下载次数: 0)
index.php
  1. <?php
  2. error_reporting(E_ALL);
  3. ini_set('display_errors', '1');
  4. include './download.php';
  5. $attachlist = explode(PHP_EOL,file_get_contents('./attachments.txt'));
  6. for($i=0;$i<100;$i++){
  7.   $is_success = download_attachment($attachlist[$i]);
  8.   if($is_success){
  9.     unset($attachlist[$i]);
  10.   }
  11. }
  12. file_put_contents('./attachments.txt',implode(PHP_EOL,$attachlist));
  13. ?>
复制代码
download.php
  1. <?php
  2. $headers = array();
  3. $headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0';
  4. $headers[] = 'Accept: image/avif,image/webp,*/*';
  5. $headers[] = 'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2';
  6. $headers[] = 'Accept-Encoding: gzip, deflate';
  7. $headers[] = 'Referer: http://kuing.orzweb.net/viewthread.php?action=printable&tid=7727';
  8. $headers[] = 'Connection: keep-alive';
  9. $headers[] = 'Cookie: GfY_sid=E6EZ66; __utma=57656496.670403294.1651855921.1651941655.1651950103.12; __utmz=57656496.1651950103.12.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); GfY_connect_is_bind=0; smile=1D1; __utmc=57656496; PHPSESSID=bhmh70fgvucko72uvio21h6i93; GfY_auth=138djJt11OYMFzjbSbQ9X2krxnAXg4S%2Fbwj4An0bQf34z1Lo8%2BcA%2F9vzbmzHV7V27HyuiG3aBgi5ce9FA6mDPoqrmZAUmvV4NUQC; __utmb=57656496.3.10.1651950103; GfY_fid5=1651946820; GfY_oldtopics=D7727D6907D9003D; __utmt=1';
  10. $headers[] = 'Pragma: no-cache';
  11. $headers[] = 'Cache-Control: no-cache';
  12. function grab_image($url,$saveto){
  13.     global $headers;
  14.     $ch = curl_init();
  15.     curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  16.     curl_setopt($ch, CURLOPT_URL, $url);
  17.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  18.     curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
  19.     $raw=curl_exec($ch);
  20.     if (curl_errno($ch)) {
  21.       echo 'Error:' . curl_error($ch);
  22.     };
  23.     curl_close ($ch);
  24.     if(file_exists($saveto)){
  25.         unlink($saveto);
  26.     }
  27.     $fp = fopen($saveto,'x');
  28.     fwrite($fp, $raw);
  29.     fclose($fp);
  30.     if(mime_content_type($saveto)=='text/html'){
  31.         unlink($saveto);
  32.         return FALSE;
  33.     }else{
  34.         return TRUE;
  35.     }
  36. }
  37. function download_attachment($path){
  38.         $parts = explode('/', $path);
  39.         if(!is_dir($dir= './'.$parts[0])) mkdir($dir);
  40.         $url = 'http://kuing.orzweb.net/attachments/'.$path;
  41.         return grab_image($url,'./'.$path);
  42. }
  43. ?>
复制代码
attachments.txt
  1. month_1308/13082221208d90b17454170aa0.jpg
  2. month_1308/13082221375ee0c789779b0980.png
  3. month_1308/1308222344148213f7290f8e26.jpg
  4. month_1308/1308231211e72f5e38638fecd6.png
  5. month_1308/1308231715893176b8d959846d.jpg
  6. month_1308/130823225250ee97a58a58f92f.jpg
  7. month_1308/13082500090783073134796064.png
  8. month_1308/13082500311e6ce3fbb6907d13.jpg
  9. month_1308/1308250031362ebc4289b54cae.jpg
  10. month_1308/1308250031ef626ca4ff4fa6de.jpg
  11. month_1308/1308251606332c0664cccf54c8.attach
  12. month_1308/13082610026c50ff1c928640cc.jpg
  13. month_1308/1308272159272f5069438853ee.png
  14. month_1308/13082819336667c6a62eba7b94.jpg
  15. month_1308/13082821091b6aa1c55037ee42.png
  16. month_1308/130828210964ac233e6a815ac4.jpg
复制代码

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2022-5-8 04:27
本帖最后由 hbghlyj 于 2024-3-31 12:39 编辑 每次尝试下载100个
下载时如果下载成功了程序就会把那一行数据删掉
然后就刷新页面就可以继续下载啦
Screenshot 2023-09-28 065221.png

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2023-9-27 02:40
致各位论坛网友:

由于 hbghlyj 操作数据库失误导致由 2023-9-26 至 2023-11-5 间期的所有帖子的内文都被清空,在此给大家真诚道歉。

现在我们正在浏览这期间的帖子,努力回忆内容,尽可能地多恢复一些,如果您还记得本帖原本的内容,也希望您能编辑回来,麻烦各位了。

730

主题

1万

回帖

9万

积分

积分
93613
QQ

显示全部楼层

kuing 发表于 2023-11-26 00:28
本帖最后由 kuing 于 2023-11-26 01:02 编辑 这帖子有点奇怪,1楼明明有两个附件,为什么没有显示出来?

想起来了,应该是你当时测试自动备份附件时删的吧。

730

主题

1万

回帖

9万

积分

积分
93613
QQ

显示全部楼层

kuing 发表于 2024-2-17 01:26
本帖最后由 kuing 于 2024-2-17 02:00 编辑 3# 丢了,我补充一下:

现在本论坛服务器目录下有一个 attachment.php 内容如下:
  1. <?php
  2. require './source/class/class_core.php';
  3. header("Content-Type: text/plain");
  4. $discuz = C::app();
  5. $discuz->init();
  6. foreach(range(0,9) as $i)
  7.     foreach(DB::fetch_all('SELECT `attachment`  FROM '.DB::table('forum_attachment_'.$i)) as $j)
  8.         foreach($j as $k)
  9.             print($k."\n");
复制代码

看起来是生成附件列表用的。

然后在 kuing.epizy.com/backup/ 下有一个 index.php 内容如下:
  1. <?php
  2. error_reporting(E_ALL);
  3. ini_set('display_errors', '1');
  4. function grab_image($url,$path){
  5.     $ch = curl_init($url);
  6.     $fp = fopen($path,'w');
  7.     if (!$fp) return -1;
  8.     curl_setopt($ch, CURLOPT_FILE, $fp);
  9.     curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
  10.     curl_exec($ch);
  11.     if (curl_errno($ch)) echo 'Error:' . curl_error($ch);
  12.     curl_close($ch);
  13.     fclose($fp);
  14.     if(filesize($path)<10)return -1;
  15.     foreach(array('302','403','429') as $err)if(filesize($path) == filesize("$err.htm") && md5_file($path) == md5_file("$err.htm"))return $err;
  16.     return 0;
  17. }
  18. function download_attachment($url,$path){
  19.     if(!is_dir($dir=dirname($path))) mkdir($dir, 0777, true);
  20.     $status = grab_image($url,$path);
  21.     if($status)unlink($path);
  22.     return $status;
  23. }
  24. $rdi = new RecursiveDirectoryIterator('.', FilesystemIterator::SKIP_DOTS);
  25. $rii = new RecursiveIteratorIterator($rdi);
  26. $files = array();
  27. if (!function_exists('str_starts_with')) {
  28.     function str_starts_with($haystack, $needle) {
  29.         return (string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
  30.     }
  31. }
  32. foreach ($rii as $di) {
  33.         $di->getPath() == '.' || str_starts_with($di->getPath(),'./deleted') || $files[] = substr($di, 2);
  34. }
  35. if (!file_exists('attachment.txt')) {
  36.         file_put_contents('attachment.txt', file_get_contents('https://kuing.cjhb.site/attachment.php'));
  37.         echo ('<h1>拉取<a href="attachment.txt">附件列表</a>完毕</h1>');
  38. }
  39. $attachlist = explode("\n", file_get_contents('attachment.txt'));
  40. $deleted = array_diff($files, $attachlist);
  41. if ($count = count($deleted)) {
  42.         echo '<h1>开始删除', $count, '个附件</h1>';
  43.         foreach ($deleted as $attach) {
  44.                 if(!is_dir($deldir = 'deleted/'.dirname($attach))) mkdir($deldir, 0777, true);
  45.                 echo "<p>$attach</p>";
  46.                 rename($attach,'deleted/'.$attach);
  47.         }
  48.         echo '<h1>删除完毕</h1>';
  49. } else
  50.         echo '<h1>没有需要删除的附件</h1>';
  51. $added = array_values(array_diff($attachlist, $files));
  52. $oldcount = count($added) - 1;
  53. if (!$oldcount) {
  54.         unlink('attachment.txt');
  55.         exit('<h1>没有需要下载的附件</h1>');
  56. }
  57. foreach ($added as $i => $attach) {
  58.         if (!$attach || $i == 1000)
  59.                 break;
  60.         $url = "https://kuing.cjhb.site/data/attachment/forum/$attach";
  61.         $status = download_attachment($url, $attach);
  62.         if ($status) {
  63.                 echo "<p style='color:red'><a href='$url'>第".($i+1)."个附件</a>下载失败:$status</p>";
  64.         } else {
  65.                 echo "<p style='color:green'><a href='$url'>第".($i+1)."个附件</a>下载成功:<a href='$attach'>打开</a></p>";
  66.                 unset($added[$i]);
  67.         }
  68. }
  69. $newcount = count($added) - 1;
  70. echo "<h1>下载了", $oldcount - $newcount, "个附件,还剩", $newcount, "个</h1>";
  71. if (!$newcount) {
  72.         unlink('attachment.txt');
  73.         echo '<h1>下载完毕</h1>';
  74. }
  75. ?>
复制代码

这个的代码太复杂,我基本看不懂,反正就是下载本论坛附件的。

另外在这个文件旁边还有一个 attachment.txt ,估计是存放附件列表的。

以前用过几次感觉挺好的。

然鹅,有一次却出现了错误,导致所有备份的附件都移到了 /deleted/ 文件夹内。
(也幸亏当时我提出需要删除的不要直接删除,而改为移走)

进入 kuing.epizy.com 的 filemanager,发现除了附件移了外,还多出了几个名字奇怪的文件夹:

QQ截图20240217011733.png

再打开 attachment.txt ,发现里面并不是附件列表,而是以下文本:
  1. <!doctype html>
  2. <html data-adblockkey="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDrp2lz7AOmADaN8tA50LsWcjLFyQFcb/P2Txc58oYOeILb3vBw7J6f4pamkAQVSQuqYsKx3YzdUHCvbVZvFUsCAwEAAQ==_NtvjDYCJoJ2iuutEE0ZcNJi1jkjX9WbYcS/Sg7GUEMJ6fcXLshfoPbtP/ydaqZsGsoirqZDWh5sS74mkMFySNQ==" lang="en">
  3. <head>
  4.     <meta charset="utf-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1">
  6.     <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC">
  7.     <link rel="preconnect" href="https://www.google.com" crossorigin>
  8. </head>
  9. <body>
  10. <div id="target" style="opacity: 0"></div>
  11. <script>window.park = "eyJ1dWlkIjoiYjc4YWYxNzUtODdkYS00Y2M2LWE4YjEtMTJmZjZhZDRmNWIyIiwicGFnZV90aW1lIjoxNzAyOTkyNjk5LCJwYWdlX3VybCI6Imh0dHA6Ly9rdWluZy5pbmZpbml0eWZyZWVhcHAuY29tL2F0dGFjaG1lbnQucGhwIiwicGFnZV9tZXRob2QiOiJHRVQiLCJwYWdlX3JlcXVlc3QiOnt9LCJwYWdlX2hlYWRlcnMiOnt9LCJob3N0Ijoia3VpbmcuaW5maW5pdHlmcmVlYXBwLmNvbSIsImlwIjoiMTg1LjI3LjEzNC42NyJ9Cg==";</script>
  12. <script src="/bhnImZNIF.js"></script>
  13. </body>
  14. </html>
复制代码

看来,就是因为这个 attachment.txt 的生成出了错,进而移走了所有附件并生成了乱78zao的文件夹。

自此之后,我就没再用它来备份附件了,还是手动备份吧——用 FileZilla 进入 FTP,把附件下载到本地,麻烦点而已。

但是,我还是想问一下楼主:
为啥会出现这种情况,以及如何改进,以避免这种情况的发生?
比如多加一个确认操作,只有当人点击确定才进行下一步移走或下载?

还有,我是否可以现在进入 https://kuing.cjhb.site/attachment.php 查看当前的所有附件的列表,复制已备份过的那些行(需要手工筛选),粘贴到 attachment.txt 里保存,再进入 kuing.epizy.com/backup/ 就会继续备份之前没备份的那些?

点评

最后这段尝试结果是不行的,看来我没理解原理。
编辑 attachment.txt 后进入 kuing.epizy.com/backup 它还是从头开始下载:
下载了1000个附件,还剩10963个  发表于 2024-2-17 02:17

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-2-17 02:02
kuing 发表于 2024-2-16 17:26
看来,就是因为这个 attachment.txt 的生成出了错,进而移走了所有附件并生成了乱78zao的文件夹。


可能是因为该网站那时被 infinityfree 暂时suspend了?

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-2-17 02:13
如果使用免费帐户 Infinityfree 有非常复杂的机制来防止机器人
那时,选择从另一台服务器获取附件的原因是两个 infinityfree 服务器之间不存在 cookie 验证机制
只有利用它我们才能轻松做简单的事情
但我不清楚为什么两个 infinityfree 服务器之间该机制不存在
所以如果放在非 infinityfree 服务器上,脚本将无法工作

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-2-17 02:19
如果使用普通账户,需要付款,但脚本很简单
例如,我正在使用 rsync 在我的服务器上进行备份,它便于使用且可靠
如果是免费帐户,编写脚本时需要想办法绕过对我们施加的限制

3149

主题

8386

回帖

6万

积分

$\style{scale:11;fill:#eff}꩜$

积分
65391
QQ

显示全部楼层

 楼主| hbghlyj 发表于 2024-2-17 02:26
所以这篇文章描述的方法并不可靠,其价值仅供学习php编程参考
对于后来的读者,请不要在生产中使用,请改用专业工具如rsync

730

主题

1万

回帖

9万

积分

积分
93613
QQ

显示全部楼层

kuing 发表于 2024-2-17 02:32
本帖最后由 kuing 于 2024-2-17 02:44 编辑 可以写一个 php 将 /deleted/ 里面的东西移回原地吗?

又或者,不移附件了,干脆把 backup/index.php 移到 backup/deleted/index.php,以后就在 backup/deleted/ 里面执行?

点评

采用后者,OK了,以后就进 backup/deleted ,其他一样,就是多套了一层文件夹。
但是如何防止下次再出错,还是得改进一下代码才行。  发表于 2024-2-17 03:06

730

主题

1万

回帖

9万

积分

积分
93613
QQ

显示全部楼层

kuing 发表于 2024-2-17 15:11
本帖最后由 kuing 于 2024-2-17 15:20 编辑
hbghlyj 发表于 2024-2-17 02:02
可能是因为该网站那时被 infinityfree 暂时suspend了?


那是不是
  1. file_put_contents('attachment.txt', file_get_contents('https://kuing.cjhb.site/attachment.php'));
复制代码

这一步在当时并没有 get 到或是 get 到了别的东西(如你说的什么验证机制)?
与平时有时网址后面会出现什么 ?i=1 的有没有关系?

那可否在这一行之后加一步,判断 attachment.txt 是不是正常的附件列表?

只要检测第一行就行了,用正则表达式看是否匹配成功,如果不成功就直接中断。
旧论坛的是 month_1306/1306271539ec06ce54cb74bd87.png 这个样子
新论坛的是 202205/15/155600rxqray04465no0yo.jpg 这个样子
代码咋写呢?我不会呀

手机版|悠闲数学娱乐论坛(第3版)

GMT+8, 2025-3-4 15:37

Powered by Discuz!

× 快速回复 返回顶部 返回列表