You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PL/SQL向Oracle插入BLOB类型base64附件的问题咨询

问题解答:BLOB字段的base64插入方式分析

你的ATTACHMENT字段插入方式是错误的,不能直接将base64格式的字符串和其他普通字段以相同方式插入,原因及正确处理方式如下:

为什么当前方式不可行

  1. 数据类型不匹配
    BLOB是二进制存储类型,而base64是文本编码格式。直接插入base64字符串,Oracle会将其作为文本的二进制形式存储,而非原始的图片/文件二进制数据,导致后续无法正常读取解析为原始文件。

  2. SQL注入风险与语法错误
    你的PL/SQL函数通过字符串拼接生成INSERT语句,当base64字符串中包含单引号、换行符等特殊字符时,会直接破坏SQL语句结构,抛出语法错误;同时这种拼接方式存在严重的SQL注入漏洞。

  3. 长度限制问题
    Oracle的VARCHAR2类型有最大长度限制(默认4000字节),长图片的base64编码很容易超过这个限制,导致数据被截断,最终存储的BLOB数据损坏。

正确的处理方案

方案1:重写PL/SQL函数,使用绑定变量处理BLOB

放弃通用拼接式的INSERT函数,针对NOTIFICATIONS表编写专用插入函数,直接接收BLOB参数,避免字符串拼接:

FUNCTION INSERT_NOTIFICATION(
    p_age_from NUMBER,
    p_age_to NUMBER,
    p_department_id NUMBER,
    p_locality_id NUMBER,
    p_message_title VARCHAR2,
    p_message_body VARCHAR2,
    p_attachment_type VARCHAR2,
    p_attachment BLOB,
    p_created_at TIMESTAMP
) RETURN BOOLEAN
AS
BEGIN
    INSERT INTO CID.NOTIFICATIONS (
        AGE_FROM, AGE_TO, DEPARTMENT_ID, LOCALITY_ID,
        MESSAGE_TITLE, MESSAGE_BODY, ATTACHMENT_TYPE,
        ATTACHMENT, CREATED_AT
    ) VALUES (
        p_age_from, p_age_to, p_department_id, p_locality_id,
        p_message_title, p_message_body, p_attachment_type,
        p_attachment, p_created_at
    );
    RETURN TRUE;
EXCEPTION
    WHEN OTHERS THEN
        RETURN FALSE;
END;

方案2:在Oracle端解码base64为BLOB(不推荐,仍有注入风险)

如果必须保留通用INSERT函数,需在VALUES中调用Oracle内置函数将base64字符串解码为BLOB:

  • 先去掉base64前缀data:image/png;base64,
  • 使用UTL_ENCODE.BASE64_DECODE + UTL_RAW.CAST_TO_RAW转换

示例values内容:

3,40,0,0,'First notification','First body notification','img',UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW('iVBORw0KGgoAAAANSUhEUgAAAQYAAABbCAIAAAAeMLz2AAAAA3NCSVQICAjb4U/g......')), sysdate

Laravel端对应处理

针对方案1,Laravel中需先将base64解码为二进制数据,再绑定为BLOB参数:

public function insertNotification(): bool {
    $base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQYAAABbCAIAAAAeMLz2AAAAA3NCSVQICAjb4U/g......';
    // 移除base64前缀
    $rawBase64 = preg_replace('#^data:image/[^;]+;base64,#', '', $base64Data);
    // 解码为二进制
    $blobData = base64_decode($rawBase64);

    $res = DB::statement(
        "DECLARE l_result BOOLEAN; BEGIN l_result := CID_UTIL_PKG.INSERT_NOTIFICATION(:age_from, :age_to, :dept_id, :locality_id, :title, :body, :attach_type, :attachment, :created_at); END;",
        [
            'age_from' => 3,
            'age_to' => 40,
            'dept_id' => 0,
            'locality_id' => 0,
            'title' => 'First notification',
            'body' => 'First body notification',
            'attach_type' => 'img',
            'attachment' => $blobData,
            'created_at' => now()
        ]
    );

    return $res;
}

总结

  • 直接插入base64字符串到BLOB字段的方式完全错误,无法得到可用的二进制数据。
  • BLOB字段不能和普通文本/数字字段用相同方式插入,必须先将base64解码为二进制,或在Oracle端完成解码转换。
  • 强烈推荐使用绑定变量的专用函数方案,既避免SQL注入,又能保证数据类型正确匹配。

内容的提问来源于stack exchange,提问作者Julián Oviedo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:12:18