Symfony 3 - 不允许序列化文件

问题描述 投票:1回答:1

我正在一个允许用户下载包的网站上工作。

我有一个包含属性(标题,注释,...)和文件属性的Packages实体。这些文件是通过VichUploaderBundle上传的。

我还有两个用户表。一个用于本地连接到站点的用户(站点上的登录表单)和CAS身份验证。

当我在CAS中进行身份验证并且我想访问显示要下载的包的页面时,我遇到了这个错误:

不允许序列化'Symfony \ Component \ HttpFoundation \ File \ File'

然而,当我在本地连接时,没有这样的问题。我不明白为什么我有这个错误。

这是我的代码:

CAS认证:成功:

/**
     * Traitement personnalisé après récupération du token
     * 
     * Il est possible d'enrichir le token (attributs...) ou d'effectuer des contrôles supplémentaire
     * 
     * @param $token 
     *      Token d'authification généré
     * 
     * @return null
     */
    public function onSuccess($token){

        $mail = $this->ai->getMail();
        $nomComplet = $this->ai->getCompletName();
        $rne = $this->ai->getRne();

        $token->setAttribute('mail', $mail);
        $token->setAttribute('nomComplet', $nomComplet);
        $token->setAttribute('rne', $rne);   
        $token->setAttribute('typeAuth','cas');

        $user = $this->checkBDD($mail); //I retrieve the user object

        $token->setAttribute('user',$user);


    }

User对象作为属性放置在令牌中。

他转到他的个人资料,其中必须包含他的信息,以及表示他已下载的软件包的表格。

/**
 * @Route ("/profile", name="user_profile")
 */
public function profileAction()
{
    $token = $this->get('security.token_storage')->getToken();
    //dump($token->getAttribute('nomComplet'));
    $user = $token->getAttribute('user');


    return $this->render('@Pages/cas/profile.html.twig');
}

Profile.html.twig:

{% extends "base.html.twig" %}
{% block body %}

{% set user = app.getToken().getAttribute('user') %}
{% dump(user) %}

{% dump(app.getToken().getAttribute('nomComplet')) %}
<div class="container">
    <h1><u>{{ user.mail }}</u></h1><br/>

    <h2>Profil</h2>

    <br/>

    <table class="table">
        <tbody>
            <tr>
                <th scope="row">Nom d'utilisateur</th>
                <td>{{app.user.username}}</td>
            </tr>
            <tr>
                <th scope="row">Email</th>
                <td>{{user.mail}}</td>
            </tr>
            <tr>
                <th scope="row">Téléchargements restants</th>
                <td>4</td>
            </tr>
        </tbody>
    </table>

    <br/><br/><br/>

    <h3> Liste des packages téléchargés </h3> <br/>
    <table class="table table-stripped">
        <thead>
            <tr>
                <th>Titre</th>
                <th>Package</th>
                <th>Notice</th>
                <th>Commentaire</th>
            </tr>
        </thead>
        <tbody>
                {% for unPackage in user.packages %}
            <tr>
                <td> {{unPackage.titre}} </td>
                <td> {{unPackage.urlPaquet}} </td>
                <td> {{unPackage.urlNotice}} </td>
                <td> {{unPackage.commentaire}} </td>
            </tr>
                {% endfor %}
        </tbody>
    </table>

    <a href="{{path('connexion_index')}}" class="btn btn-primary">Retour à l'accueil</a>
    <a href="{{ path('deconnexion') }}" class="btn btn-primary">Déconnexion</a><br/><br/><br/><br/>
    </div>

在twig中,我们检索令牌中的User属性,并显示其信息,包括其包。 (用户的packages属性是ArrayCollection,并且在ManyToMany中与Package实体相关联)

我的用户实体:

<?php

namespace Site\PagesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Site\PagesBundle\Security\Traits\traitUser;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * UserCas
 *
 * @ORM\Table(name="user_cas")
 * @ORM\Entity(repositoryClass="Site\PagesBundle\Repository\UserCasRepository")
 * @UniqueEntity("mail")
 */
class UserCas
{

    use traitUser;


    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     *
     * @ORM\Column(name="nbTelechargementsAuto", type="integer", nullable=true)
     */
    private $nbTelechargementsAuto;

    /**
     * @var bool
     *
     * @ORM\Column(name="enabled", type="boolean")
     */
    private $enabled;


    /**
     * @ORM\Column(name="mail", type="string")
     */
    private $mail;

    /**  
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="Paquet")  
     * @ORM\JoinTable(name="paquetsDDLUserCas") 
     * @ORM\JoinColumn(nullable=false)
     */  
    private $packages;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->packages = new ArrayCollection();
        $this->setEnabled(true);

    }




    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }


    /**
     * @return string
     */
    public function getMail()
    {
        return $this->mail;
    }

    public function setMail($mail)
    {
        $this->mail = $mail;
    }


    /**
     * Set enabled
     *
     * @param boolean $enabled
     *
     * @return UserCas
     */
    public function setEnabled($enabled)
    {
        $this->enabled = $enabled;

        return $this;
    }

    public function isEnabled()
    {
        return $this->enabled;
    }

}

我的包实体:

<?php

namespace Site\PagesBundle\Entity;

use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Site\PagesBundle\Entity\Paquet;
use Site\PagesBundle\Entity\TypeUser;
use Symfony\Component\HttpFoundation\File\File;
use Doctrine\Common\Collections\ArrayCollection;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Paquet
 *
 * @ORM\Table(name="paquet")
 * @ORM\Entity(repositoryClass="Site\PagesBundle\Repository\PaquetRepository")
 * @Vich\Uploadable
 */
class Paquet
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**  
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="TypeUser")  
     * @ORM\JoinTable(name="Packages_des_TypesUser") 
     * @ORM\JoinColumn(nullable=false)
     */  
    private $typeUser;

    public function __construct()
    {
        $this->typeUser = new ArrayCollection();
    }

    /** 
     * Get TypeUser 
     * 
     * @return Site\PagesBundle\Entity\TypeUser 
     */ 
    public function getTypeUser() 
    { 
        return $this->typeUser; 
    }

    public function deleteTypeFromTypesUser(TypeUser $type)
    {
        $this->typeUser->removeElement($type);
    }



    /**
     * Set typeUser
     *
     * @param Site\PagesBundle\Entity\TypeUser $typeUser
     *
     * @return Paquet
     */
    public function setTypeUser(Site\PagesBundle\Entity\TypeUser $typeUser)
    {
        $this->typeUser = $typeUser;

        return $this;
    }


    /**
     * @var string
     *
     * @ORM\Column(name="titre", type="string", length=255)
     * @Assert\Length(min=5, max=255, minMessage="Le titre doit comporter au minimum 5 caractères")
     */
    private $titre;

    /**
     * @var string
     *
     * @ORM\Column(name="urlPaquet", type="string", length=255)
     */
    private $urlPaquet;

    /**
     * @Vich\UploadableField(mapping="paquet", fileNameProperty="urlPaquet")
     * @var File
     */
    private $paquetFile;

    /**
     * @ORM\Column(type="datetime")
     *
     * @var \DateTime
    */
    private $updatedAt;

    /**
 * @param File|UploadedFile $unPaquetFile
 *
 * @return Paquet
*/
public function setPaquetFile(File $unPaquetFile = null)
{
    $this->paquetFile = $unPaquetFile;

    if ($unPaquetFile) 
    {
        $this->updatedAt = new \DateTimeImmutable();
    }


    return $this;
}

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     *
     * @return Paquet
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

/**
 * @return File|null
 */
public function getPaquetFile()
{
    return $this->paquetFile;
}


    /**
     * @var string
     *
     * @ORM\Column(name="urlNotice", type="string", length=255,nullable=true)
     */
    private $urlNotice;

    /**
     * @Vich\UploadableField(mapping="notice", fileNameProperty="urlNotice",nullable=true)
     * @var File
     */
    private $noticeFile;

    /**
     * @var string
     *
     * @ORM\Column(name="commentaire", type="text")
     */
    private $commentaire;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set titre
     *
     * @param string $titre
     *
     * @return Paquet
     */
    public function setTitre($titre)
    {
        $this->titre = $titre;

        return $this;
    }

    /**
     * Get titre
     *
     * @return string
     */
    public function getTitre()
    {
        return $this->titre;
    }

    /**
     * Set urlPaquet
     *
     * @param string $urlPaquet
     *
     * @return Paquet
     */
    public function setUrlPaquet($urlPaquet)
    {
        $this->urlPaquet = $urlPaquet;

        return $this;
    }

    /**
     * Get urlPaquet
     *
     * @return string|null
     */
    public function getUrlPaquet()
    {
        return $this->urlPaquet;
    }

    /**
     * @return File|null
     */
    public function getNoticeFile()
    {
        return $this->noticeFile;
    }

        /**
     * @param File|UploadedFile $uneNoticeFile
     *
     * @return Paquet
    */
    public function setNoticeFile(File $uneNoticeFile = null)
    {
        $this->noticeFile = $uneNoticeFile;

        if ($uneNoticeFile) 
        {
            $this->updatedAt = new \DateTimeImmutable();
        }


        return $this;
}

    /**
     * Set urlNotice
     *
     * @param string $urlNotice
     *
     * @return Paquet
     */
    public function setUrlNotice($urlNotice)
    {
        $this->urlNotice = $urlNotice;

        return $this;
    }

    /**
     * Get urlNotice
     *
     * @return string
     */
    public function getUrlNotice()
    {
        return $this->urlNotice;
    }

    /**
     * Set commentaire
     *
     * @param string $commentaire
     *
     * @return Paquet
     */
    public function setCommentaire($commentaire)
    {
        $this->commentaire = $commentaire;

        return $this;
    }

    /**
     * Get commentaire
     *
     * @return string
     */
    public function getCommentaire()
    {
        return $this->commentaire;
    }
}

就是这样,我想我把所有需要的信息都放了。我再说一遍,当我在本地验证(而不是CAS)时,我没有这个问题。我不应该正常序列化任何文件,对吧?


编辑:

在Paquet.php中,我实现了\ Serializable,以及两种方法:

  /** @see \Serializable::serialize() */
  public function serialize()
  {
      return serialize(array(
          $this->id,
          $this->noticeFile,
          $this->paquetFile,

      ));
  }

  /** @see \Serializable::unserialize() */
  public function unserialize($serialized)
  {
      list (
          $this->id,
          $this->noticeFile,
          $this->paquetFile,
      ) = unserialize($serialized, array('allowed_classes' => false));
  }

同样的错误,我的方法是好的吗?


编辑:好的它有效,我刚刚在我的UserCas.php中添加了这两个函数:

public function serialize()
{
    return serialize($this->id);
}

public function unserialize($serialized)
{
   $this->id = unserialize($serialized);

}
php file symfony serialization
1个回答
0
投票

这是我的主要猜测,它可能是也可能不是正确的答案。我倾向于可能不是正确的答案。我几乎无法使用您的代码在本地测试它。

我假设在某些时候会发生以下情况:

$serlialization = serialize($userClass);

您的用户类具有对资源流的引用,在本例中为File。哪个不能序列化。

here

资源不是要序列化的,不能通过会话变量跨页面加载持久化。它们基本上只是某些系统资源的句柄。 PHP将在脚本执行结束时自动解除分配这些资源句柄。

您必须在类上实现Serializable接口,这些接口将被序列化并具有资源引用。

让我们以Paquet类为例。

class Paquet implements \Serializable
{
    ...

    public function __clone()
    {
        // now it's a string reference not a resournce reference
        $this->noticeFile = $this->noticeFile->getPath();
         // Alternatively i think you can use base64_encode 
        $this->paquetFile = $this->paquetFile->getPath();

        // the rest can stay the same
    }

    public function serialize()
    {
        return serialize(clone $this);
    }

    public function unserialize($serialized)
    {
        // TODO: Implement unserialize() method.
    }
}

当然你不需要克隆,有其他方法。

class Paquet implements \Serializable
{
    public function serialize()
    {
        $toSerialize = new \stdClass();

        $toSerialize->noticeFile = $this->noticeFile->getPath();
        $toSerialize->paquetFile = $this->paquetFile->getPath();

        return serialize($toSerialize);
    }

    public function unserialize($serialized)
    {
        $unseriliazed = unserialize($serialized);

        $this->noticeFile = new File($unseriliazed->noticeFile);
    }
}

这应该照顾资源流引用,因为它不再是引用,它是一个字符串。

请注意,您也可以使用__sleep(),但您还必须使用__wakeup。它们与Serializable接口或多或少完全相同,你只需要编写自己的实现。


同样,这是我的主要猜测。如果不进行调整,它可能不会100%工作。