【问题标题】:Symfony Notice: unserialize(): Error at offset 36 of 40 bytes , moving from Mysql to PostgreSQLSymfony 通知:unserialize(): Error at offset 36 of 40 bytes ,从 Mysql 移动到 PostgreSQL
【发布时间】:2017-02-07 15:21:28
【问题描述】:

我在调用内部制作的 api 时遇到问题。 日志说:

[2017-02-07 16:04:39] doctrine.DEBUG: SELECT h0_.id AS id_0, h0_.hash AS hash_1, h0_.request AS request_2, h0_.options AS options_3, h0_.serialized_response_body AS serialized_response_body_4, h0_.response AS response_5, h0_.sent_at AS sent_at_6 FROM http_request h0_ WHERE h0_.hash = ? ["dd3e36a5a38618974cae2b45f9cb3a67"] []
[2017-02-07 16:04:39] request.CRITICAL: Uncaught PHP Exception Symfony\Component\Debug\Exception\ContextErrorException: "Notice: unserialize(): Error at offset 36 of 40 bytes" at /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php line 57 {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\ContextErrorException(code: 0): Notice: unserialize(): Error at offset 36 of 40 bytes at /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php:57)"} []

我有点迷茫>.

编辑:

在我的控制器中,我提交了一个包含多个信息的表单以执行该过程。

 /**
 * @Rest\View(serializerGroups={"Review"})
 * @Security("is_granted('ROLE_REVIEW_CREATE')")
 */
public function postAction(Request $request)
{
    if ($this->getUser()->getBalance()->getTokens() == 0) {
        throw new AccessDeniedException('The Review can not be created because you lack of tokens');
    }

    $review = new Review();
    $review->setCreatedBy($this->getUser());

    $reviewForm = $this->createForm(ReviewType::class, $review, [
        'csrf_protection' => false,
    ]);
    $reviewForm->submit($request->request->all());
    if ($reviewForm->isSubmitted() && $reviewForm->isValid()) {
        // If the user is in an organization, takes the organization analyzer environment, otherwise takes the user one.
        $analyzerEnvironment = $this->getUser()->getCompany() ? $this->getUser()->getCompany()->getAnalyzerEnvironment() : $this->getUser()->getAnalyzerEnvironment();

        $crawlingFlow = $this->get('app.manager.crawling_flow')->getCrawlingFlow();

        $this->get('app.manager.review')->process(
            $review,
            $crawlingFlow,
            $analyzerEnvironment
        );

        $reviewEncrypted = new ReviewEncrypted();
        $reviewEncrypted->setReliability($review->getReliability());
        $reviewEncrypted->setData($this->get('app.manager.review')->encrypt($review));
        $reviewEncrypted->setCreatedBy($this->getUser());
        $this->getDoctrine()->getManager()->persist($reviewEncrypted);
        $this->getDoctrine()->getManager()->flush();
        $review->setId($reviewEncrypted->getId());

        if ($this->getUser()->getBalance()->getTokens() > 0) {
            $this->getUser()->getBalance()->setTokens($this->getUser()->getBalance()->getTokens() - 1);
            $this->getDoctrine()->getManager()->persist($this->getUser());
            $this->getDoctrine()->getManager()->flush();
        }

        return $review;
    }

    return $reviewForm;
}

调用时:

$crawlingFlow = $this->get('app.manager.crawling_flow')->getCrawlingFlow();

    $this->get('app.manager.review')->process(
        $review,
        $crawlingFlow,
        $analyzerEnvironment
    );

调用了几个服务,它们发送请求,执行诸如存储在数据库中之类的事情......

问题是,当我更改数据库(从 mysql 到 postgresql)时,我是否忘记了做某事,或者是别的什么?

哪里可能会出现 unserialize() 错误?为什么?

感谢您的帮助:p

编辑 2:

根据日志“vendor/doctrine/dbal/lib/Doctrine/DBAL/Types/ObjectType.php line 57”,这里是错误的来源:

/**
 * {@inheritdoc}
 */
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
    return serialize($value);
}

/**
 * {@inheritdoc}
 */
public function convertToPHPValue($value, AbstractPlatform $platform)
{
    if ($value === null) {
        return null;
    }

    $value = (is_resource($value)) ? stream_get_contents($value) : $value;
    $val = unserialize($value);
    if ($val === false && $value !== 'b:0;') {
        throw ConversionException::conversionFailed($value, $this->getName());
    }

    return $val;
}

【问题讨论】:

  • 你的代码有什么问题吗?
  • 是的,数据可能会有所帮助。
  • 抱歉帖子已编辑

标签: php mysql postgresql symfony


【解决方案1】:

MySQL 和 PostgreSQL 的 text 之间有一个重要区别,可能是您的情况。 PostgreSQL 不允许在文本字段中使用 \0。因此,在第一个 \0 上准备阶段 pg 驱动程序剪切字符串。

很遗憾,serialize 在内部使用了 \0 符号。

class A {
  private $a = 'a';
  private $b = 'b';
}

$a = new A();

var_export(serialize($a));

将显示 'O:1:"A":2:{s:4:"' . "\0" . 'A' . "\0" . 'a";s:1:"a";s:4:"' . "\0" . 'A' . "\0" . 'b";s:1:"b";}'

这个刺痛的 MySQL 插入可以正常工作: INSERT INTO test1 VALUES ('O:1:\"A\":2:{s:4:\"\0A\0a\";s:1:\"a\";s:4:\"\0A\0b\";s:1:\"b\";}')

但是 Pg 驱动会默默地切字符串并执行
LOG: execute pdo_stmt_00000001: INSERT INTO test1 VALUES ($1)
DETAIL: parameters: $1 = 'O:1:"A":2:{s:4:"'
INSERT INTO test1 VALUES ('O:1:"A":2:{s:4:"') 与准备仿真。

如您所见 - 结果是剪切字符串,反序列化无法恢复它。

解决方案:对 Postgresql 使用 bytea 数据类型或添加某种序列化字符串的编码/解码。

UPD:关于 D​​octrine http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html#object 中的 object 数据类型

【讨论】:

  • 谢谢,正在研究如何实现 bytea 方式
  • 我没有得到要更改的内容?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-05
  • 2018-02-08
  • 1970-01-01
  • 2019-09-18
  • 2012-02-20
  • 1970-01-01
相关资源
最近更新 更多