0

Looking at docs I can download my git repo zip file using:

curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer <MY TOKEN>" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/<MY_GIT_NAME>/<REPO>/zipball/master --output "download.zip"

I want to use this curl from within a PHP function:

$f = fopen(__DIR__.'/download.zip', 'w+');

$ch = curl_init();
$url = "https://api.github.com/repos/$user/$repo/zipball/master";

$opt = [
    CURLOPT_URL => $url,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_FILE => $f,
];
curl_setopt_array($ch, $opt);

$headers = array(
    "Accept: application/vnd.github+json",
    "Authorization: Bearer $token",
    "X-Github-Api-Version: 2022-11-28",
);

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);

The $response is true but the zip file empty. Any ideas?

UPDATE

I am pretty sure the issue is with the curl, as it takes no time at all to execute, whereas a few seconds on the command line. Looking at the curl_getinfo as suggested it looks like I am getting http_code: 403.

I have tried adding:

$userAgent = $_SERVER['HTTP_USER_AGENT'];

and then

"User-Agent: $userAgent"

into the headers and then get http_code: 302

RGriffiths
  • 5,722
  • 18
  • 72
  • 120
  • 2
    Does it work from the command line directly with `curl` or GitHub CLI? – Azeem Apr 27 '23 at 11:50
  • if you open the downloaded zip file in a text editor such as notepad++, does it show up anything odd that you wouldn't expect (you can perhaps compare it to a copy of the same zip file you download manually yourself from Github) – ADyson Apr 27 '23 at 11:51
  • @Azeem It works from the command line. The zip folder after the php version though is 0kb, but should be 100kb. – RGriffiths Apr 27 '23 at 11:53
  • @RGriffiths: Right. Looks like you're not writing the response to file. See https://stackoverflow.com/a/7967561/7670262. – Azeem Apr 27 '23 at 11:59
  • Check what `curl_getinfo` has to say, especially regarding http_code and download_content_length. – CBroe Apr 27 '23 at 11:59
  • Does this answer your question? [PHP cURL, read remote file and write contents to local file](https://stackoverflow.com/questions/7967531/php-curl-read-remote-file-and-write-contents-to-local-file) – ADyson Apr 27 '23 at 12:08
  • @ADyson Please see the update. I think the issue is more to do with getting the data initially. – RGriffiths Apr 27 '23 at 12:19
  • I see. The most likely reason for that 403 then is that the value in `$token` is invalid or expired, or something. – ADyson Apr 27 '23 at 12:20
  • P.S. If it works from the command-line curl without the user-agent then there should be no reason to need that header in the PHP version. I think at best that might trick github into thinking you're accessing the request from a browser, and that might cause it to try and redirect to you a different, browser-friendly page perhaps (if you're getting a 302, that seems to be what occurred...in that case the response header info ought to also include Location header telling you where it tried to redirect you) – ADyson Apr 27 '23 at 12:23
  • @ADyson Good point about the User-Agent. The token is still valid as it still works from the command line. Will keep trying. – RGriffiths Apr 27 '23 at 12:28
  • Can we assume you omitted the `$token = ...` line from the PHP you've shown here, just so that you don't publicise the code? `$user` and `$repo` also don't seem to be defined anywhere - same reason? Just double-checking you didn't actually forget them entirely! :-) – ADyson Apr 27 '23 at 12:29
  • 1
    Yes - didn't want to show it. I am using the same at the one in command line. – RGriffiths Apr 27 '23 at 12:36

2 Answers2

2

Ok, so if the request is successful, it will send a 302 redirect as mentioned in the docs.

To control this, we will use CURLOPT_FOLLOWLOCATION to catch the binary response thrown for the zip file.

At my end, I was forced to add User-Agent header too without which I got the request forbidden error. So, added a User-Agent as mentioned in the docs.

Once the binary data is received, just write that in a .zip file name of your choice using file_put_contents. Below is the code that works perfectly fine at my end.

Final code:

<?php

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/repos/some-user/some-repo/zipball/master');

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Accept: application/vnd.github+json',
    'Authorization: Bearer <YOUR-TOKEN>',
    'X-GitHub-Api-Version: 2022-11-28',
    'User-Agent: Awesome-App'
]);

$res = curl_exec($ch);

curl_close($ch);

file_put_contents('repo_download.zip', $res);

Note: If you are unsure about the ref branch, just skip it so that the git system takes the default branch. From the docs,

If you omit :ref, the repository’s default branch (usually main) will be used.

nice_dev
  • 17,053
  • 2
  • 21
  • 35
  • That's excellent - thanks. Works perfectly. A follow up question - do you know if it is possible to download a folder from the repo, rather than the whole repo? – RGriffiths Apr 27 '23 at 14:21
  • @RGriffiths This [`doc`](https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content) is the closest I found. As an alternative, you can download the repo, extract the zip and only copy the folder of your choice to your required destination. – nice_dev Apr 28 '23 at 05:13
  • 1
    Cheers. I am currently using your solution to download the whole repo and extract, but I actually only want one folder. I have was looking at your doc ref but couldn't get it to work. Will keep playing around with it. Thanks for looking. – RGriffiths Apr 28 '23 at 09:09
-2

Add the following line after the curl_exec() function:

rewind($f);

This will move the file pointer back to the beginning of the file, allowing you to read the downloaded data.

Also, make sure that you have write permissions for the directory where you are trying to save the downloaded file.

Wongjn
  • 8,544
  • 2
  • 8
  • 24