Skip to content

kbsali/php-redmine-api

Repository files navigation

PHP Redmine API

A simple PHP Object Oriented wrapper for Redmine API.

Uses Redmine API.

Features

  • Follows PSR-4 conventions and coding standard: autoload friendly
  • API entry points implementation state :
  • OK Attachments
  • OK Groups
  • OK Custom Fields
  • OK Issues
  • OK Issue Categories
  • OK Issue Priorities
  • NOK Issue Relations - only partially implemented
  • OK Issue Statuses
  • OK News
  • OK Projects
  • OK Project Memberships
  • OK Queries
  • OK Roles
  • OK Time Entries
  • OK Time Entry Activities
  • OK Trackers
  • OK Users
  • OK Versions
  • OK Wiki

Todo

Limitations

Redmine is missing some APIs for a full remote management of the data :

A possible solution to this would be to create an extra APIs implementing the missing entry points. See existing effort in doing so : https://github.com/rschobbert/redmine-miss-api

Requirements

  • PHP ^7.3 || ^8.0
  • The PHP cURL extension
  • The PHP SimpleXML extension
  • The PHP JSON extension
  • PHPUnit >= 9.0 (optional) to run the test suite
  • "Enable REST web service" for your Redmine project (/settings/edit?tab=authentication)
  • then obtain your API access key in your profile page : /my/account
  • or use your username & password (not recommended)

Install

Composer

Composer users can simply run:

$ php composer.phar require kbsali/redmine-api

at the root of their projects. To utilize the library, include Composer's vendor/autoload.php in the scripts that will use the Redmine classes.

For example,

<?php
// This file is generated by Composer
require_once 'vendor/autoload.php';

$client = new Redmine\Client('http://redmine.example.com', 'username', 'password');

Manual

It is also possible to install the library oneself, either locally to a project or globally; say, in /usr/share/php.

Download the library from php-download.com. The advantage of using this site is that no Composer installation is required. This service will resolve all composer dependencies for you and create a zip archive with vendor/autoload.php for you.

Than extract the library somewhere. For example, the following steps extract v1.6.0 of the library into the vendor/php-redmine-api-1.6.0 directory:

$ unzip kbsali_redmine_api_1.6.0.0_require.zip
$ rm kbsali_redmine_api_1.6.0.0_require.zip

Now, in any scripts that will use the Redmine classes, include the vendor/autoload.php file from the php-redmine-api directory. For example,

<?php
// This file ships with php-redmine-api
require 'vendor/php-redmine-api-1.6.0/vendor/autoload.php';

$client = new Redmine\Client('http://redmine.example.com', 'username', 'password');

Running the test suite

You can run test suite to make sure the library will work properly on your system. Simply run vendor/bin/phpunit in the project's directory :

$ vendor/bin/phpunit
PHPUnit 9.5.3 by Sebastian Bergmann and contributors.

Warning:       No code coverage driver available

...............................................................  63 / 445 ( 14%)
............................................................... 126 / 445 ( 28%)
............................................................... 189 / 445 ( 42%)
............................................................... 252 / 445 ( 56%)
............................................................... 315 / 445 ( 70%)
............................................................... 378 / 445 ( 84%)
............................................................... 441 / 445 ( 99%)
....                                                            445 / 445 (100%)

Time: 00:00.102, Memory: 12.00 MB

OK (445 tests, 993 assertions)

Basic usage of php-redmine-api client

Start your project

Create your project e.g. in the index.php by require the vendor/autoload.php file.

+<?php
+
+require_once 'vendor/autoload.php';

Instantiate a Redmine Client

You can choose between the navite curl client or the PSR-18 compatible client.

Native curl Client Redmine\Client

Every Client requires a URL to your Redmine instance and either a valid Apikey...

<?php

require_once 'vendor/autoload.php';
+
+// Instantiate with ApiKey
+$client = new Redmine\Client('http://localhost', '1234567890abcdfgh');

... or valid username/password.

<?php

require_once 'vendor/autoload.php';
+
+// Instantiate with Username/Password (not recommended)
+$client = new Redmine\Client('http://redmine.example.com', 'username', 'password');

💡 For security reason it is recommended that you use an ApiKey rather than your username/password.

After you instantiate a client you can set some optional settings.

<?php

require_once 'vendor/autoload.php';

// Instantiate with ApiKey
$client = new Redmine\Client('https://redmine.example.com', '1234567890abcdfgh');
+
+// [OPTIONAL] if you want to check the servers' SSL certificate on Curl call
+$client->setCheckSslCertificate(true);
+
+// [OPTIONAL] set the port (it will try to guess it from the url)
+$client->setPort(8080);
+
+// [OPTIONAL] set a custom host
+$client->setCustomHost('https://localhost:8080');

Psr-18 compatible Client Redmine\Client\Psr18Client

The Psr18Client requires

  • a Psr\Http\Client\ClientInterface implementation (like guzzlehttp/guzzle), see
  • a Psr\Http\Message\ServerRequestFactoryInterface implementation (like nyholm/psr7), see
  • a Psr\Http\Message\StreamFactoryInterface implementation (like nyholm/psr7), see
  • a URL to your Redmine instance
  • an Apikey or username
  • and optional a password if you want tu use username/password.

💡 For security reason it is recommended that you use an ApiKey rather than your username/password.

<?php

require_once 'vendor/autoload.php';
+
+$guzzle = \GuzzleHttp\Client();
+$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();
+
+// Instantiate with ApiKey
+$client = new Redmine\Client\Prs18Client($guzzle, $psr17Factory, $psr17Factory, 'https://redmine.example.com', '1234567890abcdfgh');
+// ...or Instantiate with Username/Password (not recommended)
+$client = new Redmine\Client\Prs18Client($guzzle, $psr17Factory, $psr17Factory, 'https://redmine.example.com', 'username', 'password');
Guzzle configuration

Because the Psr18Client is agnostic about the HTTP client implementation every configuration specific to the transport has to be set to the Psr\Http\Client\ClientInterface implementation.

This means that if you want to set any cURL settings to Guzzle you have multiple ways to set them:

  1. Using Guzzle environment variables
  2. Using request options inside a Psr\Http\Client\ClientInterface wrapper:
<?php

require_once 'vendor/autoload.php';

+use Psr\Http\Client\ClientInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
$guzzle = \GuzzleHttp\Client();
$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();

+$guzzleWrapper = new class(\GuzzleHttp\Client $guzzle) implements ClientInterface
+{
+    private $guzzle;
+
+    public function __construct(\GuzzleHttp\Client $guzzle)
+    {
+        $this->guzzle = $guzzle;
+    }
+
+    public function sendRequest(RequestInterface $request): ResponseInterface
+    {
+        return $this->guzzle->send($request, [
+            // Set the options for every request here
+            'auth' => ['username', 'password', 'digest'],
+            'cert' => ['/path/server.pem', 'password'],
+            'connect_timeout' => 3.14,
+            // Set specific CURL options, see https://docs.guzzlephp.org/en/stable/faq.html#how-can-i-add-custom-curl-options
+            'curl' => [
+                CURLOPT_SSL_VERIFYPEER => 1,
+                CURLOPT_SSL_VERIFYHOST => 2,
+                CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
+            ],
+        ]);
+    }
+};
+
// Instantiate with ApiKey
-$client = new Redmine\Client\Prs18Client($guzzle, $psr17Factory, $psr17Factory, 'https://redmine.example.com', '1234567890abcdfgh');
+$client = new Redmine\Client\Prs18Client($guzzleWrapper, $psr17Factory, $psr17Factory, 'https://redmine.example.com', '1234567890abcdfgh');

Built-in Redmine features

Impersonate User

Redmine allows you to impersonate another user. This can be done using the methods startImpersonateUser() and stopImpersonateUser().

$client->startImpersonateUser('kim');
// all requests will now impersonate the user `kim`

// To stop impersonation
$client->stopImpersonateUser();

API usage

You can now use the getApi() method to create and get a specific Redmine API.

<?php

$client->getApi('user')->all();
$client->getApi('user')->listing();

$client->getApi('issue')->create([
    'project_id'  => 'test',
    'subject'     => 'some subject',
    'description' => 'a long description blablabla',
    'assigned_to_id' => 123, // or 'assigned_to' => 'user1'
]);
$client->getApi('issue')->all([
    'limit' => 1000
]);

See [example.php](example.php) for further examples.

User Impersonation

As of Redmine V2.2 you can impersonate user through the REST API :

$client = new Redmine\Client('http://redmine.example.com', 'API_ACCESS_KEY');

// impersonate user
$client->startImpersonateUser('jsmith');

// create a time entry for jsmith
$client->getApi('time_entry')->create($data);

// remove impersonation for further calls
$client->stopImpersonateUser();

Thanks!