Nextcloud 18.0.5 に PHP 7.3.18 からアクセスする方法

この記事は公開されてから時間が経っています

さくらインターネットのレンタルサーバーで動いている Nextcloud に PHP 経由でアクセスする方法
cURL を利用すると使えますが、色んな所を見て回ったけどよく解らなかったので忘れないように書いておこう

WebDAV 経由で cURL の API が Nextcloud のサイトに書いてありますので利用します

ダウンロード


$url = "https://xxxxx.sakura.ne.jp/Nextcloud/remote.php/dav/files/yyyyyyyy/Nextcloud.png";
$user = "yyyyyyyy";
$pass = "XXXXXXXX";
 
$data = '<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:"></d:propfind>';
 
$fp = fopen('tt.png',"w");
 
$curl = curl_init();
 
//curl_setopt($curl,CURLOPT_VERBOSE, true);
 
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_USERPWD,$user.":".$pass);
//curl_setopt($curl,CURLOPT_CUSTOMREQUEST,"PROPFIND");
//curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
 
// Download
 
curl_setopt($curl,CURLOPT_FILE,$fp);
curl_setopt($curl,CURLOPT_BINARYTRANSFER,true);
curl_setopt($curl,CURLOPT_WRITEFUNCTION,'filewrite');
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,"GET");
 
// cURL Download
 
$ret = curl_exec($curl);
 
echo $ret;
exit;
 
function filewrite($cp,$data){
 
global $fp;
 
$len = fwrite($fp,$data);
return $len;
}
 

こんな感じです
このソースを適当な URI で実行すると、実行したディレクトリーに Nextcloud.png が tt.png と言うファイル名でコピーされます
fopen() で用意したファイル構造体にコールバック関数で内容を書き込みます

CURLOPT_WRITEFUNCTION オプションの ‘filewrite’ は、ファイルを書き出す関数です

PHP のヘルプによると
二つのパラメータをとるコールバック。最初のパラメータは CURL リソースで、2 番目は書き込むデータの文字列です。データの保存には、 このコールバック関数を使わなければなりません。書き込んだデータの正確なバイト数を返す必要があります。返さなければ、エラーで転送が異常終了します。
となっています

ファイルリスト

コメントアウトしてありますけど、ファイルの一覧は、CURLOPT_CUSTOMREQUEST で PROPFIND を指定して、CURLOPT_POSTFIELDS に $data で指定したような XML を指定して curl_exec() します

引数の XML は、戻り値の構造を全部渡すように API の説明には書いてありますが、ここの $data 引数程度でも帰ってきました
curl をコマンドラインから実行してみるときにも data 引数になにも指定せず実行するとエラーしてしまいますが、長い引数を間違えなく指定するのが面倒なので手抜きしてみました ^^..

戻り値に $data で指定した様な XML にデータが埋まって帰ってきますので SimpleXML などで処理します
戻り値の内容は Nextcloud の API のページに書いてありますが、よく解らない戻り値が一部有ります ^^..

2020-06-09 追記:

PROPFIND のオプションに Depth:0 と言うのを指定すると、フォルダーのプロパティーが返ってくるそうです
上記の例だと、

$url = "https://xxxxx.sakura.ne.jp/Nextcloud/remote.php/dav/files/yyyyyyyy/";

curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_USERPWD,$user.":".$pass);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,"PROPFIND");
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
curl_setopt($curl,CURLOPT_HTTPHEADER,['Depth: 0']);
 
$ret = curl_exec($curl);

こんな感じで Depth: 0 を指定します
ちなみに、Depth: 3 とか指定すると深い位置までディレクトリーの中のファイル一覧を返してきます
 
ディレクトリーでは無く、ファイルを $url で指定した場合は Depth に関係なく指定したファイルのプロパティーを返してくるようです

アップロード

ファイルのアップロードも、実行するサーバーに予めファイルを格納しておきます


$url = "https://xxxxx.sakura.ne.jp/Nextcloud/remote.php/dav/files/yyyyyyyy/test.txt";
$path = 'test.txt';
$mime = "text/plain";
 
curl_setopt($curl,CURLOPT_URL,$url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl,CURLOPT_USERPWD,$user.":".$pass);
 
curl_setopt($curl,CURLOPT_PUT, true);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST,"PUT");
//curl_setopt($curl,CURLOPT_HTTPHEADER, array('Expect:'));
 
curl_setopt($curl,CURLOPT_BINARYTRANSFER,true);
 
//$ups = array( 'file' => new CURLFile($path));
//curl_setopt($curl,CURLOPT_POSTFIELDS, $ups );
 
$fp = fopen('test.txt','r');
 
curl_setopt($curl,CURLOPT_INFILE,$fp);
curl_setopt($curl,CURLOPT_INFILESIZE,filesize('test.txt'));
 
//curl_setopt($curl,CURLOPT_READFUNCTION,'fileread');
 
$handle1 = fopen("./debug.txt", "w");
curl_setopt($curl, CURLOPT_STDERR, $handle1);
 
$handle2 = fopen("./ret_header.txt", "w");
curl_setopt($curl, CURLOPT_WRITEHEADER, $handle2);
 
//curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/plain'));
 
$ret = curl_exec($curl);
 
curl_close($curl);
 
fclose($handle2);
fclose($handle1);
 
function fileread($cp,$fd,$len){
 
$data = fread($fd,$len);
 
$ret = strlen($data);
 
echo "length = ".$len."\n";
echo "data = ".$data."\n";
 
return $data;
}
 
 

試行途中の残骸も残しておこう…

残骸にもある new CURL_FILE() で何回か試したんですけど、確かにファイルはアップロードされるんですが、アップロードの際のヘッダー情報なども一緒に格納されてしまうと言う現象に当たってしまいました
fileread() みたいなコールバック関数も指定すればキチンとコールされますが、同様に何か余計な情報が付加されてしまいました
マルチパートで送信した時みたいなヘッダーでしたので、その辺りも調べたんですがよく解りませんでした

結局、CURLOUT_INFILE で指定するだけで格納出来ました…

これは、ユーザー yyyyyyyy のフォルダーのルートに、実行したディレクトリーに格納されている test.txt と言うファイルを test.txt と言うファイル名で格納します
(解りやすく名前を変えれば良かった…)

CURLOPT_STDERR や、CURLOPT_HTTPHEADER は、動作の確認に利用する事が出来ます
これは、テキストファイルを実行したディレクトリーに書き出します
エラーしないと CURLOPT_STDERR はゼロバイトのファイルになります
先頭の方に書いてある CURLOPT_VERBOSE を設定すると、詳細な情報が書き出されます

CURLOPT_READFUNCTION で参照される関数の説明は、ヘルプにこんな風に書いてあります
三つのパラメータをとるコールバック。最初のパラメータは CURL リソースで、2 番目は CURLOPT_INFILE で cURL に渡したストリームリソース、 そして最後が読み込むデータの最大量です。 コールバックは、要求したデータ量以下の長さの文字列を返さなければなりません。一般的には、渡されたストリームリソースから読み込んだデータを返します。 EOF を伝えるには空文字列を返さなければなりません。

引数の処理が上手くないような気がしますので、詳しくなった頃にでも書き直そう…

2020-06-09 追記2:

Adobe の Dreamweaver でコーディングしてプレビューをローカルで処理する場合、SSL の証明が無いとエラーします
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, false);
こんな感じで追記すると無視しますので、ローカルでも確認出来ます
 
Windows 上で PHP を PowerShell とかで動かしてプレビューとかデバッグするときに追記すると便利かもしれないです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


The reCAPTCHA verification period has expired. Please reload the page.