Upload, transform, optimize, and manage images and videos with Cloudinary from PHP — the cloudinary/cloudinary_php package on Packagist.
composer require cloudinary/cloudinary_phpSet your API environment variable (Console > Settings > API Keys):
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>Upload an image and get an optimized delivery URL:
<?php
require 'vendor/autoload.php';
use Cloudinary\Cloudinary;
use Cloudinary\Transformation\Delivery;
use Cloudinary\Transformation\Format;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Quality;
use Cloudinary\Transformation\Resize;
try {
$cloudinary = new Cloudinary();
// Upload a remote image (a local file path works the same way).
$result = $cloudinary->uploadApi()->upload(
'https://res.cloudinary.com/demo/image/upload/sample.jpg',
['public_id' => 'quickstart-sample']
);
echo 'Uploaded: ', $result['public_id'], PHP_EOL;
// Build a 400x400 auto-cropped URL with automatic format and quality.
$url = $cloudinary->image($result['public_id'])
->resize(Resize::fill(400, 400)->gravity(Gravity::auto()))
->delivery(Delivery::format(Format::auto()))
->delivery(Delivery::quality(Quality::auto()));
echo 'Optimized URL: ', $url, PHP_EOL;
} catch (Throwable $e) {
fwrite(STDERR, 'Quick start failed: ' . $e->getMessage() . PHP_EOL);
fwrite(STDERR, 'Check that CLOUDINARY_URL is set (Console > Settings > API Keys).' . PHP_EOL);
exit(1);
}Save as quickstart.php and run php quickstart.php. Create a free account if you don't have one — or run npx @cloudinary/cloud to provision one without signing up.
uploadApi(), adminApi(), and searchApi() are methods — call them with parentheses.
- Get Cloudinary credentials
- Import and call the SDK
- Configure Cloudinary
- Upload an image
- Upload a large video
- Sign a browser upload
- Transform and deliver an image
- Transform and deliver a video
- Search and manage assets
- Moderate an upload
- Use structured metadata
- Use a custom HTTP client
- Troubleshoot errors
Runnable versions live in examples/ — each is a complete file you can run directly.
Use this package in PHP server-side code: uploads, signed operations, asset administration, search, moderation, and delivery URL generation. It works with any framework, and with none.
For other jobs, better-fitting tools exist:
- Laravel-native integration with facades and a storage driver:
cloudinary-labs/cloudinary-laravel. - WordPress, Magento, and similar platforms: platform integrations (md).
- Browser or frontend framework rendering: frontend SDKs (md).
- Complete in-browser upload UI: Upload Widget (md).
- Text-to-image generation and image-to-video: platform APIs (md), not wrapped by this package.
- Multi-step media workflow automation: MediaFlows (md).
- Interactive agent-driven asset operations: Cloudinary MCP servers and Skills (md).
The full capability map — plus the Skills, MCP servers, and CLI worth setting up first — is in docs/platform-capabilities.md.
Stable, actively maintained. See CHANGELOG.md.
| SDK version | PHP |
|---|---|
| 3.x | 8.0 and later |
| 2.x | 5.6 – 8.3 (no longer maintained) |
| 1.x | 5.4 – 7.x (no longer maintained) |
The 1.x series lives on the support/1.x branch. Moving from it? See the migration guide (md).
- Bundled task docs — ship inside the package, version-matched.
- PHP SDK guide — the full documentation (md).
- Transformation and API reference (md).
Documentation links in this README point at the browsable HTML page, with an (md)
companion link that returns the same page as raw Markdown. Inside docs/ and examples/
the links are Markdown-only, since those files are written to be read by coding agents.
Either form works for any page: add .md for Markdown, drop it for HTML.
By default the SDK sends requests with its own Guzzle client. To route them through your own PSR-18 client, with its logging, retries, proxy and timeouts:
use Cloudinary\Cloudinary;
use GuzzleHttp\Psr7\HttpFactory;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Psr18Client;
$cloudinary = new Cloudinary();
$cloudinary->setHttpClient(new Psr18Client(HttpClient::create(), new HttpFactory(), new HttpFactory()));Any Psr\Http\Client\ClientInterface works. API objects created with new take the client
through their own setHttpClient(), or Cloudinary::setDefaultHttpClient() sets it for the
whole process. With a custom client, timeout, connection_timeout and api_proxy are
configured on your client, and *Async() calls run one at a time. Every request carries
an Authorization header with your API secret: redact it if your client logs headers.
Details: Use a custom HTTP client.
- Contributing to this repo: read AGENTS.md.
- Using the installed package: the docs in
vendor/cloudinary/cloudinary_php/docs/match your installed version and are the source of truth; start with platform-capabilities before assuming a feature exists.
- SDK bugs and feature requests: GitHub issues
- Account and platform questions: Cloudinary support
See SECURITY.md for private vulnerability reporting. Keep your
api_secret in server-side code; for client uploads, use the server-signed pattern in
Sign a browser upload.
Released under the MIT license — see LICENSE. Copyright (c) Cloudinary Ltd.