轶哥

📚 Having fun with AI Agent. Always learning.

    PHP实现Github头像缓存

    在开发博客Github登录功能,缓存Github头像的时候,发现下载头像是个很费劲的事情。

    利用位于HK的PHP虚拟主机,可以轻松解决这个问题。

    伪静态依赖Apache的Rewrite模块。

    PHP代码

    // 屏蔽所有报错,避免图片加载失败
    error_reporting(0);
    
    // 设置需要返回的头名称
    $proxied_headers = array('Set-Cookie', 'Content-Type', 'Cookie', 'Location');
    
    // 获取URL路径
    $proxy_request_url = $_SERVER['REQUEST_URI'];
    
    // 设置请求地址HOST
    $github_res_host = 'githubusercontent.com';
    
    // 设置当前PHP文件所在相对路径,根目录设置为"/"
    $proxy_base_url = '/avatar';
    
    // 如果包含 /index.php 路径
    if (strpos($proxy_request_url, $proxy_base_url . '/index.php') === 0) {
        // 兼容非伪静态模式
        $proxy_request_url = ltrim(substr($proxy_request_url, strlen($proxy_base_url . '/index.php')), '/');
    } else {
        // 依赖Apache的Rewrite模块
        $proxy_request_url = ltrim(substr($proxy_request_url, strlen($proxy_base_url)), '/');
    }
    
    // 判断请求地址是否符合$github_res_host规定,防止滥用
    if (strpos(substr($proxy_request_url, 0, strpos($proxy_request_url, '/')), $github_res_host) === false) {
        die("403");
    }
    
    // 最终请求的远程地址
    $proxy_request_url = "https://" . $proxy_request_url;
    
    // 初始化 CURL
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $proxy_request_url);
    curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    
    // 设置请求的 Cookie,此处用不到
    // if (isset($_SERVER['HTTP_COOKIE'])) {
    //   $client_headers[] = "Cookie: " . $_SERVER['HTTP_COOKIE'];
    // }
    
    // 设置请求的 User-Agent
    if (isset($_SERVER['HTTP_USER_AGENT'])) {
        $client_headers[] = "User-Agent: " . $_SERVER['HTTP_USER_AGENT'];
    }
    
    curl_setopt($ch, CURLOPT_HTTPHEADER, $client_headers);
    
    $res = curl_exec($ch);
    curl_close($ch);
    
    // 解析请求到的结果
    list($headers, $body) = explode("\r\n\r\n", $res, 2);
    
    $headers = explode("\r\n", $headers);
    $hs = array();
    
    foreach ($headers as $header) {
        if (false !== strpos($header, ':')) {
            list($h, $v) = explode(':', $header);
            $hs[$h][] = $v;
        } else {
            $header1 = $header;
        }
    }
    
    // 设置返回头
    list($proto, $code, $text) = explode(' ', $header1);
    header($_SERVER['SERVER_PROTOCOL'] . ' ' . $code . ' ' . $text);
    
    foreach ($proxied_headers as $header_name) {
        if (isset($hs[$header_name])) {
            foreach ($hs[$header_name] as $v) {
                if ($header_name !== 'Set-Cookie') {
                    header($header_name . ": " . $v, false);
                } else {
                    header($header_name . ": " . $v);
                }
            }
        }
    }
    
    die($body);
    

    伪静态配置

    Apache伪静态配置文件.htaccess

    RewriteEngine on
    RewriteBase /avatar
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond $1 !^(index\.php)
    RewriteRule ^(.*)$ index.php?/$1 [L]
    

    开启伪静态前:https://域名/avatar/index.php/avatars2.githubusercontent.com/u/6657330?v=4

    开启伪静态后:https://域名/avatar/avatars2.githubusercontent.com/u/6657330?v=4

    测试地址:https://apio.xyz/avatar/avatars2.githubusercontent.com/u/6657330?v=4

    JavaScript使用示例

    const avatorDownloadURL = 'https://apio.xyz/avatar/' + avatarURL.replace('https://', '')
    

    如此,GitHub OAuth 第三方登录缓存头像时便可快速下载。

    为什么不直接使用URL参数?

    通过拼接路径并直接返回图片Header头(Content-Type是对应图片的格式)的方式,方便直接在前端<img>标签中引用图片,浏览器兼容性更好。实际使用时建议同步下载图片后上传到对象存储。

    打赏
    交流区(6)
    凉拌萝卜丝不好吃吗

    666

    2020年7月23日 06:50回复
    轶哥

    😄

    2020年7月23日 06:51回复
    小苦瓜一点也不苦

    有意思

    2020年7月23日 09:45回复
    小苦瓜一点也不苦

    可以🉑

    2020年7月23日 09:49回复
    遇见卡瓦博格

    666

    2020年7月23日 09:53回复
    轶哥

    赶紧给你博客也加上登录!!😂

    2020年7月23日 09:54回复
    尚未登陆
    发布
      上一篇 (将新网址推送到百度、谷歌、Bing搜索引擎)
    下一篇 (解决XML报错:Input is not proper UTF-8, indicate encoding)  

    评论回复提醒