最近有点散漫了,有点想法但是不多,不想动手,其实留的摊子还不上,每次说要去解决一下吧,就拖到不知道什么时候,这个性子不行,抽点时间这个搞一下那个也看一下的,效率也不行浪费时间倒是不少,本来这个的上传内容老早就要写的,一直拖到了今天写完。

这次主要说的一个就是一个 github 的接口调用,为了下一步的做的前端上传附件文件做基础准备,之前也说过要改办一下网站后台的上传部分,事出原因是前段时间 jsdelivr 的加速链接一直失效,导致网站页面里面的图片很多都加载不出来,为了省一点流量和cdn加速,所以吧图片的资源都放 GitHub 上了,但是这个 GitHub 有时候也抽风的,连进去官网就很慢,而且图片也不是直接给你用,所以才有了这次的这个小小的修改。

因为这次用的是改版一下网站后台的功能,所以就这个上传的功能也是用的 PHP 的方式写,本人不是后端的开发者,在实际操作的时候还是踩了坑和遇到问题的,但幸运的是我这边的功能也不是很多,新增删除修改查询基础的几样就可以满足我的需求了,可以看一下官方文档。
v3版API的文档链接
v3版API的官方教程

再开始前先把我们的GitHub 仓库地址个新建一个,不然下面都不知道往哪去新增数据了,GitHub 是一个面向开源及私有软件项目的托管平台,可以把自己的文件代码等都传上去,然后在可以使用 jsdelivr cdn 加速文件可以让其在国内访问。

新建 GitHub 仓库

GitHub 官网新建一个仓库

git

创建一个有 repo 权限的 GitHub Token

git1

然后点击 Generate token 按钮,即可生成一个token,如下图:

git2

新生成的 Token 只会显示一次,请妥善保存!如有遗失,重新生成即可。


下面就展开来说一下怎么去调用这些接口把文件传到GitHub上。

权限认证 Authentication

做任何接口的对接都少不了认证这一块,基本上都需要你的凭证才能给你信息,不然所有人都能无限制调用接口就乱套了,这里也是一样,针对这个凭证就是你在 GitHub 上公开仓库的 token 值。查了一下资料有很多种认证方式,我这边没做的很麻烦就是写在 header 里面,通过 Authorization: token OAUTH-TOKEN 的方式传过去就可以。
代码中可以这么写:

$header = array(
  "Content-Type:application/vnd.github.v3.json",
  "User-Agent:" . $options->GithubRepo,
  "Authorization: token " . $options->GithubToken
);

GithubRepo 是需要传入的仓库名字, GithubToken 是需要传入的仓库 token,这样我们的请求设置就做好了。

新增文件 Create content

有了上面的 header 之后就通过 GitHub 提供的上传新建接口实现新增,在这之前需要对上传的文件进行 base64 处理,这个是文档必须的。 官方文档

$fileContent = file_get_contents($uploadfile);
$data = array(
  "message" => "Upload file " . $fileName,
  "content" => base64_encode($fileContent),
);

可以使用 curl 封装一个方法统一调用。

function cosCurl($url, $header, $type, $data)
{
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type);
  if (strpos($url, 'https') !== false) {
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  }
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  $output = curl_exec($ch);
  $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  curl_close($ch);

  return array(
    "output" => $output,
    "code" => $code
  );
}

// 拿到上面设置的 header 做验证信息
$result = self::cosCurl(
  "https://api.github.com/repos/" . $options->GithubUser . "/" . $options->GithubRepo . "/contents" . $path_relatively,
  $header,
  "PUT",
  $data
);

最后成功会返回一个 201 的成功的状态码,成功之后再同时写入文件到本地服务,以防链接失效可用。

更新文件 Upload content

更新文件不必新增的简单,需要先拿到文件对应的 sha 码才可以进行操作,在 GitHub 中的文件都有类似的标识就是 sha 码,拿到需要修改文件的 sha 码再对文件进行重新上传即可完成更新。

获取 sha 码也可以用到上面的公共请求方法,只不过在请求的时候不需要传入 $data 值。可以提取一个公共方法来操作,因为后面的删除也需要对文件进行获取 sha。拿到我们需要的识别码之后就可以对文件进行修改了,注意了这一步一定要在操作文件之前获取,如果code 返回 200 那就是修改成功。具体代码。

$sha = self::getGithubSha("https://api.github.com/repos/" . $options->GithubUser . "/" . $options->GithubRepo . "/contents" . $github_path);
$data = array(
  "message" => "Modify file " . str_replace(self::getUploadDir(), "", $content['attachment']->path),
  "content" => base64_encode($fileContent),
  "sha" => $sha,
);
// 获取 sha 
function getGithubSha($path)
{
  $header = array(
    "Content-Type:application/json",
    "User-Agent:" . $options->GithubRepo,
    "Authorization: token " . $options->GithubToken
  );

  $result = self::cosCurl($path, $header, "GET", array());
  return json_decode($result['output'], true)['sha'];
}

删除文件 Delete content

删除文件可以修改文件差不多,唯一的区别就是需要在传入文件了,但是唯一的编码还是要加上,因为要确定是针对哪个文件进行操作。

$sha = self::getGithubSha("https://api.github.com/repos/" . $options->GithubUser . "/" . $options->GithubRepo . "/contents" . $github_path);
$data = array(
  "message" => "Delete file",
  "sha" => $sha,
);

按照上面两个照葫芦画瓢的操作,知道服务器返回状态码 200 就算是成功删除了。

结尾

这次是在主题的代码直接改写的,后续想做一个插件放出来,考虑在多加几个 cdn 支持,再把上传图片的压缩处理一下,上传自动压缩可能上传慢一点但是前端访问的快啊。