Openssl error string: примеры (PHP)

Использование openssl_error_string для отладки операций OpenSSL
Раздел: Шифрование (OpenSSL)
openssl_error_string: string|false

Основные сведения о функции openssl_error_string

Функция openssl_error_string() возвращает текстовое описание последней ошибки, произошедшей в расширении OpenSSL. Эта функция не принимает параметров и вызывается после неудачных операций с криптографическими алгоритмами.

Назначение функции

Использование функции актуально при выполнении операций шифрования, расшифровки, подписи и проверки подписей, генерации ключей, работы с сертификатами X.509. Функция помогает в отладке, предоставляя человекочитаемые сообщения об ошибках из библиотеки OpenSSL.

Возвращаемое значение

Возвращает строку с описанием ошибки или false, если в стеке ошибок OpenSSL больше нет сообщений. Для получения всех ошибок необходимо вызывать функцию в цикле до получения значения false.

Особенности работы

Каждый вызов функции возвращает следующую ошибку из стека и удаляет ее оттуда. Стек ошибок очищается при успешных операциях. Сообщения об ошибках накапливаются только при неудачных вызовах функций OpenSSL.

Простые примеры использования

Пример 1: Получение одной ошибки
<?php
// Пытаемся расшифровать данные с неправильным ключом
$data = 'зашифрованные данные';
$key = 'неверный ключ';
$method = 'AES-256-CBC';

$result = openssl_decrypt($data, $method, $key);

if ($result === false) {
    $error = openssl_error_string();
    echo "Ошибка: $error";
}
?>
Ошибка: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Пример 2: Получение всех ошибок из стека
<?php
// Выполняем несколько операций с ошибками
openssl_pkey_get_private('invalid_key');
openssl_sign('data', $signature, 'wrong_key', OPENSSL_ALGO_SHA256);

// Получаем все ошибки
while ($errorMsg = openssl_error_string()) {
    echo "$errorMsg\n";
}
?>
error:0909006C:PEM routines:get_name:no start line
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

Альтернативные функции в PHP

openssl_get_errors()

Функция возвращает массив всех ошибок из стека OpenSSL без их удаления. Полезно для логирования всех ошибок перед очисткой стека.

<?php
openssl_pkey_get_public('invalid');
$errors = openssl_get_errors();
print_r($errors);
?>
Array
(
    [0] => error:0909006C:PEM routines:get_name:no start line
)
Исключения с openssl_error_string()

Можно создавать пользовательские исключения с сообщениями об ошибках OpenSSL для более структурированной обработки.

<?php
function decryptData($data, $key) {
    $result = openssl_decrypt($data, 'AES-256-CBC', $key);
    if ($result === false) {
        throw new Exception('Ошибка расшифровки: ' . openssl_error_string());
    }
    return $result;
}
?>

Распространенные ошибки

Ошибка 1: Вызов до операции OpenSSL
<?php
// Неправильно: вызов без предшествующей операции OpenSSL
$error = openssl_error_string();
echo $error ?: "Нет ошибок";
?>
Нет ошибок
Ошибка 2: Неправильная интерпретация false
<?php
// Опасный код: false может быть интерпретировано как строка
$error = openssl_error_string();
if ($error) { // false преобразуется в пустую строку
    echo "Ошибка: $error";
}
// Лучше использовать строгое сравнение
if ($error !== false) {
    echo "Ошибка: $error";
}
?>
Ошибка 3: Потеря ошибок при множественных вызовах
<?php
openssl_encrypt('data', 'unknown_cipher', 'key');
// Получаем первую ошибку
$error1 = openssl_error_string();
// Получаем вторую ошибку (если есть)
$error2 = openssl_error_string();
// Если была только одна ошибка, $error2 будет false
?>

Изменения в новых версиях PHP

PHP 8.0 и выше

В PHP 8 улучшена обработка ошибок OpenSSL. Некоторые функции теперь выбрасывают исключения вместо молчаливого возврата false. Однако openssl_error_string() сохраняет обратную совместимость и продолжает работать.

Изменения в поведении

С версии PHP 7.4 улучшена очистка стека ошибок. Теперь при успешных операциях стек очищается более предсказуемо. В ранних версиях могли оставаться устаревшие сообщения об ошибках.

Рекомендации для PHP 8+

В современном коде рекомендуется использовать механизм исключений в сочетании с openssl_error_string() для получения детальной информации:

<?php
try {
    $key = openssl_pkey_get_private('invalid_key');
    if ($key === false) {
        throw new RuntimeException('Ошибка ключа: ' . openssl_error_string());
    }
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

Расширенные примеры применения

Пример 1: Обертка для логирования ошибок
Пример php
<?php
class OpenSSLDebugger {
    private static $errors = [];
    
    public static function executeWithLogging(callable $opensslOperation) {
        $result = $opensslOperation();
        
        if ($result === false) {
            while ($error = openssl_error_string()) {
                self::$errors[] = [
                    'time' => date('Y-m-d H:i:s'),
                    'message' => $error
                ];
            }
        }
        
        return $result;
    }
    
    public static function getErrors() {
        return self::$errors;
    }
}

// Использование
$data = 'test';
$encrypted = OpenSSLDebugger::executeWithLogging(
    fn() => openssl_encrypt($data, 'AES-256-CBC', 'key', 0, 'iv')
);

print_r(OpenSSLDebugger::getErrors());
?>
Пример 2: Анализ ошибок по шаблонам
Пример php
<?php
function categorizeOpenSSLError($errorString) {
    $patterns = [
        'bad_decrypt' => '/bad decrypt/i',
        'key_error' => '/key.*error|password.*wrong/i',
        'format_error' => '/PEM routines|bad base64/i',
        'algorithm_error' => '/algorithm.*not found/i'
    ];
    
    foreach ($patterns as $category => $pattern) {
        if (preg_match($pattern, $errorString)) {
            return $category;
        }
    }
    return 'unknown';
}

// Тестирование
openssl_decrypt('data', 'AES-256-CBC', 'wrong_key');
$error = openssl_error_string();
$category = categorizeOpenSSLError($error);

echo "Категория ошибки: $category\n";
echo "Текст ошибки: $error";
?>
Категория ошибки: bad_decrypt
Текст ошибки: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Пример 3: Восстановление после ошибок
Пример php
<?php
function tryMultipleDecryptions($encryptedData, $possibleKeys) {
    foreach ($possibleKeys as $key) {
        $result = openssl_decrypt(
            $encryptedData, 
            'AES-256-CBC', 
            $key, 
            OPENSSL_RAW_DATA, 
            'initialization_vector'
        );
        
        if ($result !== false) {
            return $result;
        }
        
        // Логируем ошибку для этого ключа
        $error = openssl_error_string();
        error_log("Не удалось расшифровать с ключом: $key. Ошибка: $error");
    }
    
    return false;
}

$keys = ['key1', 'key2', 'correct_key'];
$decrypted = tryMultipleDecryptions($encryptedData, $keys);
?>

Аналоги в других языках программирования

Python: исключения cryptography
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

try:
    public_key.verify(
        signature,
        data,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
except InvalidSignature as e:
    print(f"Ошибка проверки подписи: {e}")
JavaScript (Node.js): объект ошибки
const crypto = require('crypto');

try {
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
} catch (error) {
    console.error(`Ошибка расшифровки: ${error.message}`);
}
MySQL: функции шифрования

MySQL возвращает NULL или сообщения об ошибках через механизм исключений СУБД, а не через отдельную функцию получения ошибок.

SELECT AES_DECRYPT('invalid_data', 'key');
-- Результат: NULL с установленным предупреждением

PHP openssl_error_string function comments

En
Openssl error string Return openSSL error message