Git Product home page Git Product logo

ocis-php-sdk's Introduction

Build Status Coverage Code Smells Quality Gate Status Security Rating

ocis-php-sdk

This SDK allows you to interact with ownCloud Infinite Scale (oCIS) storage using PHP.

Documentation

You can find a rendered version of the API documentation in our dev docs.

To render the documentation locally, use the phpDocumentor to run it in the local repo. E.g.:

docker run --rm -v ${PWD}:/data phpdoc/phpdoc:3

After that you will find the documentation inside the docs folder.

Installation via Composer

Add "owncloud/ocis-php-sdk" to the require block in your composer.json and then run composer install.

Warning

The ocis-php-sdk currently relies on a development version of the "owncloud/libre-graph-api-php" package. To ensure proper dependency resolution, it is necessary to set "minimum-stability": "dev" and "prefer-stable": true in your composer.json file.

{
    "minimum-stability": "dev",
    "prefer-stable": true,
    "require": {
        "owncloud/ocis-php-sdk": "^1.0"
    }
}

Alternatively, you can simply run the following from the command line:

composer config minimum-stability dev
composer config prefer-stable true
composer require owncloud/ocis-php-sdk

Getting started

Create an Ocis object using the service Url and an access token:

$ocis = new Ocis('https://example.ocis.com', $accessToken);

Acquiring an access token is out of scope of this SDK, but you can find examples for that below.

Also refreshing tokens is not part of the SDK, but after you got a new token, you can update the Ocis object:

$ocis->setAccessToken($newAccessToken);

Drives (spaces)

Drives can be listed using the getAllDrives or the getMyDrives method.

The Drive class is responsible for most file/folder related actions, like listing files, creating folders, uploading files, etc.

// get the personal drive of the authorized user
// `getMyDrives` returns all drives that the user is a member of
// but in this example the result is filtered to only return
// the personal drive (parameter 3 = DriveType::PERSONAL)
$drives = $ocis->getMyDrives(
    DriveOrder::NAME,
    OrderDirection::ASC,
    DriveType::PERSONAL
);

// get the drive id
$id = $drives[0]->getId();

// get the name of the drive
$name = $drives[0]->getName();

// get a link to the drive that can be opened in a browser and will lead the user to the web interface 
$webUrl = $drives[0]->getWebUrl();

// create a folder inside the drive
$drives[0]->createFolder("/documents");

// upload a file to the drive
$drives[0]->uploadFile("/documents/myfile.txt", "Hello World!");

// get an array of all resources of the "/documents" folder inside the drive
$resources = $drives[0]->getResources("/documents");

Notifications

Notifications can be listed using the getNotifications method, which will return an array of Notification objects representing all active notifications.

The Notification object can retrieve details of the corresponding notification and mark it as read (delete).

Sharing

Given the correct permissions, an OcisResource can be shared with a group or a user. To define the access permissions of the receiver every share has to set SharingRole(s).

// get the resources of a subfolder inside a drive
$resources = $drive->getResources("/documents");

// get all roles that are possible for that particular resource
$roles = $resources[0]->getRoles();

// find the role that is allowed to read and write the shared file or folder 
for ($roles as $role) {
    if ($role->getDisplayName() === 'Can edit') {
        $editorRole = $role;
        break;
    }
}

// find all users with a specific surname
$users = $ocis->getUsers("einstein")[0];

// share the resource with the users
$resources[0]->invite($users, $editorRole);

Requirements

  • PHP 8.1 or higher
  • oCIS 5.0.0 or higher

Acquiring an Access Token

For an easier experience in acquiring an access token, several PHP OIDC client libraries are available. The following code snippet showcases how to retrieve an access token with the facile-it/php-openid-client library.

Install PHP dependencies

You can install the facile-it/php-openid-client library using composer:

composer require facile-it/php-openid-client
composer require nyholm/psr7

Required PHP Libraries

  • php-bcmath
  • php-gmp

Code Snippet to Fetch an Access Token

<?php
	
	require __DIR__ . '/path/to/vendor/autoload.php';
	
	use Facile\OpenIDClient\Client\ClientBuilder;
	use Facile\OpenIDClient\Issuer\IssuerBuilder;
	use Facile\OpenIDClient\Client\Metadata\ClientMetadata;
	use Facile\OpenIDClient\Service\Builder\AuthorizationServiceBuilder;
	use Nyholm\Psr7\ServerRequest;
	
	$issuer = (new IssuerBuilder())
		->build('https://example.ocis.com');
	
	$clientMetadata = ClientMetadata::fromArray([
		'client_id' => 'client_id',
		'client_secret' => 'client_secret',
		'redirect_uris' => [
			'http://url-of-this-file',
		],
	]);
	$client = (new ClientBuilder())
		->setIssuer($issuer)
		->setClientMetadata($clientMetadata)
		->build();
	
	
	$authorizationService = (new AuthorizationServiceBuilder())->build();
	$redirectAuthorizationUri = $authorizationService->getAuthorizationUri(
		$client,
		['scope'=>'openid profile email offline_access']
	);
	
	
	if(!isset($_REQUEST["code"])) {
		header('Location: ' . $redirectAuthorizationUri);
	} else {
		$serverRequest = new ServerRequest('GET', $_SERVER['REQUEST_URI']);
		
		$callbackParams = $authorizationService->getCallbackParams($serverRequest, $client);
		
		$tokenSet = $authorizationService->callback($client, $callbackParams);
		
		// store access and refresh token in database
		$accessToken = $tokenSet->getAccessToken();
		echo 'AccessToken : ' . $accessToken;
		echo '<hr>';
		
		$refreshToken = $tokenSet->getRefreshToken();
		echo 'RefreshToken : ' . $refreshToken;
		echo '<hr>';
		
		// use this code to get new access token when expired
		$tokenSet = $authorizationService->refresh($client, $refreshToken);
		$accessToken = $tokenSet->getAccessToken();
		echo 'NewAccessToken : ' . $accessToken;
	}

If you're working in a development environment where you might need to bypass SSL verification (though this is not advised for production environments), here's how:

<?php
	...
	use Facile\OpenIDClient\Issuer\Metadata\Provider\MetadataProviderBuilder;
	use Facile\JoseVerifier\JWK\JwksProviderBuilder;
	use Symfony\Component\HttpClient\Psr18Client;
	use Symfony\Component\HttpClient\CurlHttpClient;
	
	$symHttpClient = new CurlHttpClient([
		'verify_peer' => false,
		'verify_host' => false
	]);
	$httpClient  = new Psr18Client($symHttpClient);
	
	$metadataProviderBuilder = (new MetadataProviderBuilder())
		->setHttpClient($httpClient);
	$jwksProviderBuilder = (new JwksProviderBuilder())
		->setHttpClient($httpClient);
	$issuer = (new IssuerBuilder())
		->setMetadataProviderBuilder($metadataProviderBuilder)
		->setJwksProviderBuilder($jwksProviderBuilder)
		->build('https://example.ocis.com');
	...
	$client = (new ClientBuilder())
		->setHttpClient($httpClient)
		->setIssuer($issuer)
		->setClientMetadata($clientMetadata)
		->build();
	
	$authorizationService = (new AuthorizationServiceBuilder())
		->setHttpClient($httpClient)
		->build();
	...

To test, simply open a browser and head to http://url-of-this-file.

Development

Integration tests

To run the tests locally

  1. Install and setup docker (min version 24) and docker compose (min version 2.21).

  2. Ensure that the following php dependencies are installed for executing the integration tests:

    - php-curl
    - php-dom
    - php-phpdbg
    - php-mbstring
    - php-ast
    
  3. add these lines to your /etc/hosts file:

    127.0.0.1	ocis.owncloud.test
    127.0.0.1	keycloak.owncloud.test
    
  4. run whole tests

    make test-php-integration        // start a full oCIS server with keycloak and other services using docker before running tests
    
  5. run single test

    make test-php-integration testGetResources   // start a full oCIS server with keycloak and other services using docker before running single test
    

    If something goes wrong, use make clean to clean the created containers and volumes.

ocis-php-sdk's People

Contributors

individual-it avatar phil-davis avatar amrita-shrestha avatar s-panta avatar nirajacharya2 avatar micbar avatar saw-jan avatar

Stargazers

 avatar  avatar David Walter avatar

Watchers

Paul Neubauer avatar Klaas Freitag avatar Juan Pablo Villafañez avatar  avatar  avatar  avatar Prarup Gurung avatar Markus Feilner avatar Roman Perekhod avatar  avatar  avatar Salipa Gurung avatar  avatar

Forkers

fschade

ocis-php-sdk's Issues

add enable drive

it's already possible using PATCH request, see what web is doing

improve docs

  • how to install using composer
  • delete "under development line"
  • check if the rest of docs still works

fix coverage

the coverage dropped after we started testing with ocis stable-5 and master
on the surface the name of the coverage file is just wrong, expected: clover-php-integration-8.1.xml real clover-php-integration-8.1-stable.xml
but the deeper problem is that we actually create the coverage twice, for master and stable branch, and we should not do that

urlencoding for special characters in user given parameters

if an user gives an input like philosophy-haters the - character gives error

OpenAPI\Client\ApiException: [400] Client error: `GET https://ocis.owncloud.test/graph/v1.0/groups?%24search=philosophy-&%24orderby=displayName` resulted in a `400 Bad Request`

Release v1.0.0-rc2

PR #198 fixed the spelling of public method isClientSynchronized
That is a backward-compatibility break, so it would be good to make a next release candidate, and we can update consumers (moodle integration) to use that.

(And whatever other changes have happened since RC1)

Decoding of tokens fails in some cases

Some tokens including special characters cannot be decoded properly by function base64_decode used here:

$plainPayload = base64_decode($tokenDataArray[1], true);

Here is an example token which fails:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE3MDgzMjU2MjEsImV4cCI6MTczOTg2MTYyMSwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkJhcnR1IiwiU3VybmFtZSI6Ikt1cnV0bHVvxJ9sdSIsIkVtYWlsIjoianJvY2tldEBleGFtcGxlLmNvbSIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdLCJEaXNwbGF5IE5hbWUiOiJCYXJ0dSBLdXJ1dGx1b8SfbHUifQ.3s4NiJYFIqzwgAY0yTlCYEkruMAafWUTJJwtEH2Br0I

The token will be properly decoded by \Firebase\JWT\JWT::urlsafeB64Decode for example.

review all skipped tests

there are still some tests skipped, need to review them and check if they are now fixed in ocis

sanitize the service URL

Check whether the URL passed to the Ocis is in proper format so that the client can handle the request properly.

bump ocis version

I think tests fail because password is mandatory for links on the newest ocis

split lines with lenght of more than 120char

Most of the issues reported by sonarcloud are too long phpstan lines, we can split them like that:

diff --git a/src/Drive.php b/src/Drive.php
index 7fdd8ab..5f498c7 100644
--- a/src/Drive.php
+++ b/src/Drive.php
@@ -30,7 +30,12 @@ class Drive
     private string $webDavUrl = '';
 
     /**
-     * @phpstan-var array{'headers'?:array<string, mixed>, 'verify'?:bool, 'webfinger'?:bool, 'guzzle'?:\GuzzleHttp\Client}
+     * @phpstan-var array{
+     *                      'headers'?:array<string, mixed>,
+     *                      'verify'?:bool,
+     *                      'webfinger'?:bool,
+     *                      'guzzle'?:\GuzzleHttp\Client
+     *                   }
      */
     private array $connectionConfig;
     private Configuration $graphApiConfig;
@@ -39,7 +44,12 @@ class Drive
     /**
      * @ignore The developer using the SDK does not need to create drives manually, but should use the Ocis class
      *         to get or create drives, so this constructor should not be listed in the documentation.
-     * @phpstan-param array{'headers'?:array<string, mixed>, 'verify'?:bool, 'webfinger'?:bool, 'guzzle'?:\GuzzleHttp\Client} $connectionConfig
+     * @phpstan-param array{
+     *                       'headers'?:array<string, mixed>,
+     *                       'verify'?:bool,
+     *                       'webfinger'?:bool,
+     *                       'guzzle'?:\GuzzleHttp\Client
+     *                    } $connectionConfig
      * @throws \InvalidArgumentException
      */
     public function __construct(

id in PROPFIND when an item is still in post-processing

this needs more debugging and some decisions.
When we tried the SDK today with @fschade, the SDK would not return an id for a file that was still in post-processing.

What do we want to do with those files? Not show them in getResources or somehow mark them?

@fschade can e.g. sharing operations happen on files that are still in post-processing?

move getPersonalDrive function in OcisPhpSdkTestCase

There are many codes like this in our integration test file

$personalDrive = $this->ocis->getMyDrives(
            DriveOrder::NAME,
            OrderDirection::ASC,
            DriveType::PERSONAL
        )[0];

We have getPersonalDrive function inside OcisTest. Maybe it can be moved to OcisPhpSdkTestCase so that we don't repeat the code to get Personal drive?

Increase test coverage

Currently, we have little test coverage for integration test. We can increase test covergae
Add tests for

  • invite #77
  • sharewithme
  • sharebyme

problem with CI when an other PR updates the composer dependencies

The PR #148 changed the phpunit dependency, but now other builds fail:
https://drone.owncloud.com/owncloud/ocis-php-sdk/832/10/3

+ composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.
- Required (in require-dev) package "phpunit/phpunit" is in the lock file as "10.5.3" but that does not satisfy your constraint "^9.6".
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require-r

run tests with ocis 5.0 stable and master

currently we run the tests only with ocis master branch, but the supported version is ocis 5.0, so in my opinion we should run the integration tests with ocis 5.0 AND ocis master

add tests for guest users

"guest" users in ocis are users that have the "User Light" role.
Probably the existing ocis-php-sdk can make use of users that have role "User Light", but we should test that.

  • add tests for creating and deleting "User Light" users (maybe we can't do that?)
  • add tests for sharing with "User Light" users

Adjust ocis-php-sdk as needed to make it work.
Report any blockers in libre-graph-api-php or ocis that prevent this from working.

Throw proper error message while tests fails

Currently, error messages are not thrown if the integration test fails. Without an error message we have to debug more so i think proper messgae should be throen in some location in integration test

setup CI

There are already some tests available (codestyle, phan, php-stan, unit), so we should run them in CI

Add delete user from group

In sdk, group can be created. Group class contains a method to delete and addUser in it. We can add a method to make API request which delete users from group

Resolve ToDos in ocis.php related to OdataError

https://github.com/owncloud/ocis-php-sdk/blob/main/src/Ocis.php has some ToDos about calls that might return an OdataError object.

        if ($allDrivesList instanceof OdataError) {
            // ToDo: understand how this can happen, and what to do about it.
            throw new InvalidResponseException(
                "listAllDrives returned an OdataError - " . $allDrivesList->getError()
            );

If something goes wrong in the underlying calls down the stack and across to the server, then libre-graph-api calls can return an OdataError object, rather than throwing ApiException.

Sort out what to do if this happens at run-time.

naming conventions

what should we call methods that return a set of items?
Currently we have:

  • Ocis::listAllDrives
  • Ocis::listMyDrives
  • Ocis::getNotifications
  • Drive::listResources

And we are about to add in #55

  • Group::getGroupTypes
  • Group::getMembers
  • Ocis::listGroups

so should it be get... or list... or maybe even find..?

Document testing part

Add some documentation inside tests directory about testing involve in sdk.

Currently while running unit tests error is thrown

└ make test-php-unit 
vendor/bin/phpunit --configuration ./phpunit.xml --testsuite unit
PHPUnit requires the "dom", "json", "libxml", "mbstring", "tokenizer", "xml", "xmlwriter" extensions, but the "dom", "mbstring", "xml", "xmlwriter" extensions are not available.
make: *** [Makefile:24: test-php-unit] Error 1

Fixes

  • need to install mbstring in php8.2

Run php phan test gives following error

vendor/bin/phan --config-file .phan/config.php --require-config-exists
ERROR: The php-ast extension must be loaded in order for Phan to work. Either install and enable php-ast, or invoke Phan with the CLI option --allow-polyfill-parser (which is noticeably slower)
php-ast can be installed in the following ways:

1. Unix (PECL): Run 'pecl install ast' and add extension=ast.so to your php.ini.

2. Unix (Compile): Download https://github.com/nikic/php-ast then compile and install the extension as follows:

   cd path/to/php-ast
   phpize
   ./configure
   make
   sudo make install

   Additionally, add extension=ast.so to your php.ini file.
For more information, see https://github.com/phan/phan/wiki/Getting-Started#installing-dependencies
make: *** [Makefile:39: test-php-phan] Error 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.