# PHP Extension Testing Guide

**Last Updated:** 2026-01-15

## Overview

This guide explains how to test PHP extension fallback logic to ensure code works correctly even when extensions are not available in production.

## Testing Objectives

1. **Verify fallback logic** activates when extensions are missing
2. **Ensure graceful degradation** - code continues to work
3. **Validate error handling** - appropriate logging and error messages
4. **Test functionality** - core features still work with fallbacks

## Testing Methods

### Method 1: Test Script (Recommended)

**Run comprehensive fallback tests:**

```bash
php v2/scripts/dev-helpers/test-extension-fallbacks.php
```

**With verbose output:**

```bash
php v2/scripts/dev-helpers/test-extension-fallbacks.php --verbose
```

**Expected output:**

- ✅ All tests pass
- Fallback functions work correctly
- Extension checks function properly

### Method 2: Manual Extension Disabling

**Temporarily disable extension in php.ini:**

1. **Find php.ini:**

   ```bash
   php --ini
   ```

2. **Edit php.ini:**

   ```ini
   ; Comment out extension line
   ; extension=mbstring
   ```

3. **Restart PHP-FPM:**

   ```bash
   sudo service php-fpm restart
   ```

4. **Run tests:**

   ```bash
   php v2/scripts/dev-helpers/test-extension-fallbacks.php
   ```

5. **Re-enable extension:**

   ```ini
   extension=mbstring
   ```

6. **Restart PHP-FPM again**

**Note:** This method may not work in all environments. Use test script instead.

### Method 3: Simulated Testing

**Create test script that simulates missing extensions:**

```php
<?php
// Temporarily override extension_loaded
$original_extension_loaded = 'extension_loaded';
if (!function_exists('test_extension_loaded')) {
    function test_extension_loaded($name) {
        // Simulate missing mbstring
        if ($name === 'mbstring') {
            return false;
        }
        return extension_loaded($name);
    }
}

// Test fallback logic
// ...
```

## Testing Scenarios

### Scenario 1: mbstring Missing

**Test case:**

- Disable mbstring extension
- Run code that uses mbstring functions
- Verify fallback logic activates
- Verify functionality still works

**Expected behavior:**

- Code executes without fatal errors
- Fallback functions are used
- Error log shows fallback usage
- Core functionality preserved

**Test script:**

```php
<?php
require_once 'v2/helpers/php-extensions.php';

// Test mbstring fallback
$text = 'Test text: äöüß';
$length = safe_mb_strlen($text, 'UTF-8');
echo "Length: {$length}\n";

// Should work even if mbstring missing
assert($length > 0, "Length should be greater than 0");
```

### Scenario 2: curl Missing

**Test case:**

- Disable curl extension
- Run code that makes HTTP requests
- Verify fallback to file_get_contents
- Verify requests still work

**Expected behavior:**

- Code uses file_get_contents if available
- Error logged if both unavailable
- Graceful error handling

**Test script:**

```php
<?php
if (function_exists('curl_init')) {
    $ch = curl_init($url);
    // ... curl code
} elseif (ini_get('allow_url_fopen')) {
    $response = file_get_contents($url);
} else {
    error_log("cURL and allow_url_fopen both unavailable");
    throw new RuntimeException('HTTP client not available');
}
```

### Scenario 3: gd Missing

**Test case:**

- Disable gd extension
- Run code that processes images
- Verify fallback skips image processing
- Verify code continues without errors

**Expected behavior:**

- Image processing skipped
- Original images used
- Error logged
- No fatal errors

## Test Checklist

### Pre-Testing

- [ ] Extension validator passes: `php v2/scripts/dev-helpers/check-php-extensions.php`
- [ ] Pre-deployment check passes: `php v2/scripts/dev-helpers/pre-deployment-check.php`
- [ ] Code reviewed for extension checks

### During Testing

- [ ] Run fallback test script
- [ ] Test with extension enabled (normal operation)
- [ ] Test with extension disabled (if possible)
- [ ] Verify fallback logic activates
- [ ] Check error logs for fallback usage
- [ ] Verify functionality still works

### Post-Testing

- [ ] All tests pass
- [ ] Error logs reviewed
- [ ] Functionality verified
- [ ] Documentation updated

## CI/CD Integration

### GitHub Actions

```yaml
name: Test Extension Fallbacks

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.0"
          extensions: mbstring, iconv, curl, json
      - name: Test fallbacks
        run: php v2/scripts/dev-helpers/test-extension-fallbacks.php
```

### GitLab CI

```yaml
test_fallbacks:
  image: php:8.0
  script:
    - php v2/scripts/dev-helpers/test-extension-fallbacks.php
```

## Production Validation

### After Deployment

1. **Check diagnostic endpoint:**

   ```
   https://www.ordio.com/v2/api/php-extensions-diagnostics.php
   ```

2. **Verify extensions loaded:**

   - All required extensions present
   - Optional extensions status noted

3. **Monitor error logs:**

   - Check for fallback usage
   - Verify no fatal errors
   - Review warning messages

4. **Test critical functionality:**
   - Blog FAQ schema generation
   - API endpoints
   - Image processing (if applicable)

## Troubleshooting

### Tests Fail

**Symptoms:**

- Fallback test script fails
- Functions not available

**Solutions:**

1. **Check extension availability:**

   ```bash
   php -m | grep mbstring
   ```

2. **Verify helper functions loaded:**

   ```php
   require_once 'v2/helpers/php-extensions.php';
   var_dump(function_exists('safe_mb_strlen'));
   ```

3. **Check file paths:**
   - Verify helper file exists
   - Check include paths

### Fallback Not Working

**Symptoms:**

- Code fails even with fallback
- Fatal errors occur

**Solutions:**

1. **Verify fallback logic:**

   ```php
   if (!function_exists('mb_strlen')) {
       error_log("mb_strlen not available, using fallback");
       // Fallback code
   }
   ```

2. **Check error logs:**

   - Look for fallback usage messages
   - Check for fatal errors

3. **Test fallback directly:**
   ```php
   $length = safe_mb_strlen($text, 'UTF-8');
   var_dump($length);
   ```

## Best Practices

1. **Always test fallbacks** before deployment
2. **Use test script** for comprehensive testing
3. **Monitor error logs** for fallback usage
4. **Document fallback behavior** in code comments
5. **Test incrementally** - one extension at a time

## Related Documentation

- `v2/scripts/dev-helpers/test-extension-fallbacks.php` - Test script
- `docs/development/PHP_EXTENSION_FALLBACK_PATTERNS.md` - Fallback patterns
- `docs/development/PHP_EXTENSION_DEPENDENCIES.md` - Extension dependencies
- `v2/helpers/php-extensions.php` - Helper functions

## Summary

1. **Run test script** before deployment
2. **Test with extensions disabled** if possible
3. **Verify fallback logic** activates correctly
4. **Check error logs** for fallback usage
5. **Validate functionality** still works

**Remember**: Testing fallbacks prevents production failures. Always test before deploying.
