> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# PHP sample projects


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

## Product Catalog app

The [Product Catalog app](https://github.com/cloudinary-devs/php-product-catalog) 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.

> **See also**:
>
> For a detailed description of the image and video workflows in this app, see the [AI Image Workflows](https://cloudinary.com/blog/ai-image-workflows-php) and [AI Video Workflows](https://cloudinary.com/blog/ai-video-workflows-with-php-and-cloudinary-from-upload-to-delivery) 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](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](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

### 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; ?>
```

> **See the full code**:
>
> * [Explore the Product Catalog app on GitHub](https://github.com/cloudinary-devs/php-product-catalog).
