使用 PHP 从 Drupal 中的路径获取文件

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

我正在使用 Drupal 开发自定义模块。用户上传一个 .zip 文件(该 zip 文件包含许多 .docx 文件),解压 .zip 文件并创建节点。

对于每个 .docx 文件,都会使用文件内容创建一个节点,并将实际文件作为附件。

我可以成功上传 .zip、解压 .zip、读取每个 .docx、使用 .docx 的内容创建节点,但我唯一不知道的是如何将 .docx 添加为附件。


这里有相当多的代码,你不需要深入查看所有代码,我已经在代码的每个“块”中添加了注释,说明它的作用,重要的部分我已经简要解释了.


我的代码的小指南:

在此函数中,我基本上创建了一个表单,以便用户可以上传 zip 文件。这里没有问题。

 public function buildForm(array $form, FormStateInterface $form_state) {
    $form['zip_file'] = [
      '#type' => 'managed_file',
      '#title' => $this->t('Upload Zip File'),
      '#description' => $this->t('Upload a zip file containing Word documents.'),
      '#upload_validators' => [
        'file_validate_extensions' => ['zip'],
      ],
      '#required' => TRUE,
      '#upload_location' => 'temporary://word_document_import', // Custom upload location

    ];
  
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
    return $form;
  }

在下一个函数中,我基本上获取 .zip,将其解压,然后使用解压的文件作为节点创建的参数进行传递。

在这里,我认为可能有一些可能,以便可以将

\Drupal\file\Entity\File
实体传递到函数中,而不是我现在拥有的
SplFileInfo
实体。

更具体地说,当我检查传递给

createDecisionNode()
的内容时,这里:
$this->createDecisionNode($file_entity, $docx_file, $form_state);
,我可以看到
$docx_file
=

SplFileInfo {#1336 ▼
  path: "/var/www/html/tmp/word_document_import/Files"
  filename: "file-sample_100kB.docx"
  basename: "file-sample_100kB.docx"
  pathname: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
  extension: "docx"
  realPath: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
  aTime: 2024-04-23 13:03:25
  mTime: 2024-04-23 12:17:02
  cTime: 2024-04-23 13:03:25
  inode: 8269895
  size: 111303
  perms: 0100644
  owner: 1000
  group: 1000
  type: "file"
  writable: true
  readable: true
  executable: false
  file: true
  dir: false
  link: false
}

因此,我当前获得的格式并不是真正可以在节点中用作附件的文件。

  public function submitForm(array &$form, FormStateInterface $form_state) {
    /* GET THE UPLOADED .ZIP */
    $file = $form_state->getValue('zip_file')[0];
    $file_entity = \Drupal\file\Entity\File::load($file);
    if (!$file_entity) {
      $form_state->setError($form['zip_file'], $this->t('Unable to load the uploaded zip file.'));
      return;
    }
  
    /* EXTRACT THE FILES FROM THE .ZIP */
    $file_path = \Drupal::service('file_system')->realpath($file_entity->getFileUri());
    $temp_dir = 'temporary://word_document_import';
    $temp_dir = \Drupal::service('file_system')->realpath($temp_dir);
    if (!file_exists($temp_dir)) {
      \Drupal::service('file_system')->mkdir($temp_dir, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
      ksm("FILE DOES NOT EXIST");
    }
    $zip = new ZipArchive();
    if ($zip->open($file_path) === TRUE) {
      $zip->extractTo($temp_dir);
      $zip->close();
    } else {
      $form_state->setError($form['zip_file'], $this->t('Failed to extract the zip file.'));
      return;
    }
    $original_filename = $file_entity->getFilename();
    $zip_filename = pathinfo($original_filename, PATHINFO_FILENAME);
    $zip_filename = preg_replace('/_\d+$/', '', $zip_filename);
    $temp_dir_without_suffix = $temp_dir . '/' . $zip_filename; // the folder here with the extracted files
    if (!file_exists($temp_dir_without_suffix)) {
      $temp_dir_with_suffix = $temp_dir . '/' . $original_filename;
      if (file_exists($temp_dir_with_suffix) && is_dir($temp_dir_with_suffix)) {
        $temp_dir_without_suffix = $temp_dir_with_suffix;
      }
    }
    
    /* GET THE EXTRACTED FILES */
    $docx_files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($temp_dir_without_suffix));

    /* CREATE NODES USING .DOCX FILES */
    foreach ($docx_files as $docx_file) {
      if ($docx_file->isFile() && $docx_file->getExtension() === 'docx') {
        $this->createDecisionNode($file_entity, $docx_file, $form_state);
      }
    }

    /* DELETE THE TEMORARY DIRECTORY */
    if (file_exists($temp_dir_without_suffix) && is_dir($temp_dir_without_suffix)) {
      $files = new \RecursiveIteratorIterator(
        new \RecursiveDirectoryIterator($temp_dir_without_suffix, \RecursiveDirectoryIterator::SKIP_DOTS),
        \RecursiveIteratorIterator::CHILD_FIRST
      );
      foreach ($files as $file) {
        if ($file->isDir()){
          rmdir($file->getRealPath());
        } else {
          unlink($file->getRealPath());
        }
      }
      rmdir($temp_dir_without_suffix);
    }

    /* REDIRECT TO CONTENTS PAGE */
    $form_state->setRedirect('system.admin_content');
  }

转到

createDecisionNode()
,我正在使用之前传递的
$file_entity
。问题是
$file_entity
不是 .docx 文件,而是 .zip 文件。因此,所有正在创建的节点都不会获得与其内容相对应的 .docx,而是获得从表单上传的 .zip。

  protected function createDecisionNode($file_entity, $docx_file, FormStateInterface $form_state) {
    $text_content = $this->readDocxFile($docx_file->getPathname());
    $filename = pathinfo($docx_file->getFilename(), PATHINFO_FILENAME);
    $file = \Drupal\file\Entity\File::load($file_entity->id());

    $node = Node::create([
      'type' => 'decision',
      'title' => $filename,
      'field_attachment' => [
        'target_id' => $file->id(),
      ],
      'field_decision_text' => [
        'value' => $text_content,
        'format' => 'full_html',
      ],
    ]);

    $node->save();
  }

现在我基本上正在尝试做的事情,因为我已将所有这些信息传递给我的

createDecisionNode()

SplFileInfo {#1336 ▼
  path: "/var/www/html/tmp/word_document_import/Files"
  filename: "file-sample_100kB.docx"
  basename: "file-sample_100kB.docx"
  pathname: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
  extension: "docx"
  realPath: "/var/www/html/tmp/word_document_import/Files/file-sample_100kB.docx"
  aTime: 2024-04-23 13:03:25
  mTime: 2024-04-23 12:17:02
  cTime: 2024-04-23 13:03:25
  inode: 8269895
  size: 111303
  perms: 0100644
  owner: 1000
  group: 1000
  type: "file"
  writable: true
  readable: true
  executable: false
  file: true
  dir: false
  link: false
}

有没有办法使用文件的路径(因为我已经有了它),并从那里获取文件,以便可以在 Node 字段中传递它?

或者也许有其他更好的方法来做到这一点?如有任何帮助,我们将不胜感激。

php ms-word drupal docx
1个回答
0
投票

首先,您应该将 .docx 文件保存在永久路径上,然后再删除临时文件夹。

之后,您应该使用此保存的文件作为您的

createDecisionNode
方法的参数。

无需将

$file_entity
传递给创建方法,因为您应该使用 .docx 文件 ID 作为
field_attachment => target_id
的值。

© www.soinside.com 2019 - 2024. All rights reserved.