Programmable Media

PHP sample projects

Last updated: Feb-03-2025

We've created a sample project to get you started with integrating Cloudinary into your PHP application.

Product Catalog app

The Product Catalog app provides a dynamic solution for managing a back office product catalog with rich media and metadata. It showcases a complete image and video workflow, from upload to delivery. Each product includes a name, metadata (SKU, price, and category), an AI-generated description, an image, and a video—all seamlessly integrated with Cloudinary for advanced media management.

PHP Product Catalog Sample App - Add Product PHP Product Catalog Sample App - View Products

See also
For a detailed description of the image and video workflows in this app, see the AI Image Workflows and AI Video Workflows blog posts.

Features

  • General functionality

    • Add new products to the catalog.
    • View all products stored in the database.
    • Explore individual product details with comprehensive metadata, image, and video.
    • Edit product details as needed.
  • Image workflow

    • Client-side upload: Upload images directly from the client side using the Upload Widget, eliminating backend dependencies.
    • AI-generated descriptions: Leverage Cloudinary’s AI Content Analysis to auto-generate captions for images.
    • Metadata management: Save user-entered product information as metadata in Cloudinary for easy retrieval.
    • Database integration: Store details including Cloudinary public IDs for streamlined delivery.
    • Dynamic delivery: Generate URLs with on-the-fly transformations, including resizing, cropping, and overlays.
  • Video workflow

    • Client-side upload: Upload videos directly from the client side using the Upload Widget, bypassing backend processes.
    • Asynchronous moderation: Ensure video compliance through AI-driven content moderation.
      • Approved videos are rendered on the page when manually refreshed.
      • Rejected videos are flagged with actionable feedback.
    • Enhanced playback: Use Cloudinary's Video Player for seamless video rendering.
    • Optional:
      • Webhook integration: Receive real-time notifications for moderation results.
      • Live updates: Product pages auto-refresh to automatically display the latest approved videos.

This app serves as a robust starting point for building an e-commerce platform or any application requiring integrated image and video workflows.

See the Product Catalog app in Action

Video Player is loading.
Current Time 0:00
Duration 0:00
Loaded: 0%
Stream Type LIVE
Remaining Time 0:00
 
1x
  • descriptions off, selected
  • captions off, selected

    Code example: Image and video processing

    Here's an excerpt from the code showing how to handle image and video processing after a client-side upload. It includes adding user-provided metadata and initiating automated video moderation.

    public/product_submission.php
    PHP
    <?php
    require_once __DIR__ . '/../vendor/autoload.php';
    require_once __DIR__ . '/../includes/database.php';
    require_once __DIR__ . '/../includes/functions.php';
    require_once __DIR__ . '/../config/cloudinary_config.php';
    
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
        $name = $_POST['name'];
        $sku = $_POST['sku'];
        $price = $_POST['price'];
        $category = $_POST['category'];
        // Get external ids for metadata fields.
        $allFieldsResponse = $api->listMetadataFields();
        $allFields = $allFieldsResponse['metadata_fields'] ?? [];    
        $externalIds=[];
        checkAndAppendExternalId($allFields, "Description", $externalIds);
        checkAndAppendExternalId($allFields, "SKU", $externalIds);
        checkAndAppendExternalId($allFields, "Price", $externalIds);
        checkAndAppendExternalId($allFields, "Category", $externalIds);
    
        // Set up metadata entries for submission to Cloudinary
        $metadata = 
        $externalIds['SKU'] . '=' . $sku . '|' .
        $externalIds['Category'] . '=["' . $category . '"]|' .
        $externalIds['Price'] . '=' . $price . '|' .
        $externalIds['Description'] . '=' . $description;
    
        // Handle image metadata updates
        if (!empty($_POST['image_url'])) {
            $product_image_url = $_POST['image_url']; // Retrieve the secure URL from the form submission
            $image_public_id = $_POST['image_id']; // Retrieve the public ID from the form submission
            // Update metadata
            $cloudinary_result = $cld->uploadApi()->explicit($image_public_id, ["type"=>"upload","metadata" => $metadata]);
            $image_caption = $cloudinary_result['info']['detection']['captioning']['data']['caption'] ?? null; // Save the image alt text from the response
        } else {
            // If there's no image, set values to null.
            $product_image_url = null;
            $image_public_id = null;
            $image_caption = null;
        }
    
        // Handle video moderation and metadata
        if (!empty($_POST['video_url'])) {
            $product_video_url = $_POST['video_url'];
            // Hold the video public ID temporarily until moderation status is confirmed.
            $video_public_id_temp = $_POST['video_id'];
            // Set metadata and mark the video for moderation.
            $cloudinary_result = $cld->uploadApi()->explicit($video_public_id_temp, ['type' => 'upload', 'resource_type' => 'video', 'moderation' => 'aws_rek_video', "metadata" => $metadata]);
            // Set initial values, pending moderation
            $product_video_url = null; 
            $video_public_id = "pending";
            $video_moderation_status="pending";     
        } else {
            // Set values in case there's no video.
            $product_video_url="invalid";
            $video_public_id = "invalid";
            $video_moderation_status=null;
            $video_public_id_temp=null;
        }
        // Save the values in the database.
        $product_id = saveProduct($pdo, $name, $product_image_url, $product_video_url, $image_public_id,  $video_public_id, $video_moderation_status, $image_caption, $video_public_id_temp);
        header("Location: products.php");
        exit;
    }
    ?>

    Code example: Smart image cropping and overlay

    Here's an excerpt showing smart cropping the image and adding an overlay:

    public/products.php
    PHP
    if ($product['image_public_id']) {
        // Create the image transformation to smart-crop the image to a square and overlay a watermark.
        $image_url = $cld->image($product['image_public_id'])
            ->resize(
                Resize::fill()
                    ->width(500)
                    ->height(500)
                    ->gravity(Gravity::autoGravity())
            )
            ->overlay(
                Overlay::source(Source::image("cloudinary_logo1")->resize(Resize::scale()->width(50)))
                    ->position(
                        (new Position())
                            ->gravity(Gravity::compass(Compass::northEast()))
                            ->offsetX(10)
                            ->offsetY(10)
                    )
            )
            ->toUrl();
    
    }

    Code example: Video rendering

    Here's an excerpt rendering the approved video using Cloudinary's Video Player:

    public/products.php
    PHP
    <!-- Display product video if available -->
    <?php if ($product['video_public_id'] && $product['video_public_id']!='pending' && $product['video_public_id']!='invalid' && $product['video_moderation_status']!='rejected'): ?>
        <div>
            <video id="doc-player" controls muted class="cld-video-player cld-fluid"></video>
        </div>
        <script>
            // Initialize the Cloudinary video player with a unique ID
            const player = cloudinary.videoPlayer('doc-player', { cloudName: '<?php echo $_ENV['CLOUDINARY_CLOUD_NAME']; ?>' });
            player.source('<?php echo $product['video_public_id']; ?>');
        </script>
    <?php elseif (isset($message)): ?>
        <p><?php echo htmlspecialchars($message); ?></p>
    <?php endif; ?>

    ✔️ Feedback sent!