concrete5.7 and 8 のファイル名の仕組み


## サーバー上に保存される物理ファイルのファイル名

- 最大127文字の半角英数字、下線(_)とドット(.)のみ
- ドイツ語、ギリシャ語、トルコ語、ロシア語、その他東ヨーロッパ系言語のラテン系文字のアクセント文字は半角英字のものに変換される
- 全角と半角ファイルが混同しているファイルは、半角文字部分だけが取り出される
- 全角日本語のみのファイル名であれば md5 のランダムなハッシュファイル名となる
- 最初や最後に _ (アンダースコアー)がある場合は削除される

## ファイル属性「タイトル」

日本語ファイル名がそのまま入ります。
プログラム的な制約はないので、使用する OS の日本語ファイル名の制約に準じます。

参考: Windows のファイル命名規則
https://support.microsoft.com/ja-jp/help/879749
- 半角で 215 文字、全角では 107 文字までの名前が付けられます。
- スラッシュ (/)、円記号 (\)、不等号記号 (<>)、アスタリスク (*)、疑問符 (?)、ダブル クォーテーション (")、縦棒 (|)、コロン (:)、セミコロン (;) をファイル名の一部に使用することはできません。

参考: OS X：プラットフォームをまたがるファイル名のベストプラクティスおよび命名規則
https://support.apple.com/ja-jp/HT202808
- 255 字まで (半角)


## concrete5 で処理をしている場所メモ

ここでファイル入力処理
/concrete/src/File/Importer.php

concrete5 V8 Git のコード

```
    /**
     * Imports a local file into the system. The file must be added to this path
     * somehow. That's what happens in tools/files/importers/.
     * If a $fr (FileRecord) object is passed, we assign the newly imported FileVersion
     * object to that File. If not, we make a new filerecord.
     *
     * @param string $pointer path to file
     * @param string|bool $filename
     * @param File|FileFolder|bool $fr
     *
     * @return number Error Code | \Concrete\Core\EntiFile\Version
     */
    public function import($pointer, $filename = false, $fr = false)
    {
        if ($filename == false) {
            // determine filename from $pointer
            $filename = basename($pointer);
        }

        $fh = Loader::helper('validation/file');
        $fi = Loader::helper('file');
        $cf = Core::make('helper/concrete/file');
        $sanitizedFilename = $fi->sanitize($filename);

        // test if file is valid, else return FileImporter::E_FILE_INVALID
        if (!$fh->file($pointer)) {
            return self::E_FILE_INVALID;
        }

        if (!$fh->extension($filename)) {
            return self::E_FILE_INVALID_EXTENSION;
        }

        if ($fr instanceof FileEntity) {
            $fsl = $fr->getFileStorageLocationObject();
        } else {
            $fsl = StorageLocation::getDefault();
        }
        if (!($fsl instanceof \Concrete\Core\Entity\File\StorageLocation\StorageLocation)) {
            return self::E_FILE_INVALID_STORAGE_LOCATION;
        }

        // store the file in the file storage location.
        $filesystem = $fsl->getFileSystemObject();
        $prefix = $this->generatePrefix();

        try {
            $src = fopen($pointer, 'rb');
            $filesystem->writeStream($cf->prefix($prefix, $sanitizedFilename), $src, array(
                'visibility' => AdapterInterface::VISIBILITY_PUBLIC,
                'mimetype' => Core::make('helper/mime')->mimeFromExtension($fi->getExtension($sanitizedFilename)),
            ));
        } catch (\Exception $e) {
            return self::E_FILE_UNABLE_TO_STORE;
        }

        if (!($fr instanceof FileEntity)) {
            // we have to create a new file object for this file version
            $fv = File::add($sanitizedFilename, $prefix, array('fvTitle' => $filename), $fsl, $fr);

            foreach ($this->importProcessors as $processor) {
                if ($processor->shouldProcess($fv)) {
                    $processor->process($fv);
                }
            }

            $fv->refreshAttributes($this->rescanThumbnailsOnImport);
        } else {
            // We get a new version to modify
            $fv = $fr->getVersionToModify(true);
            $fv->updateFile($sanitizedFilename, $prefix);
            $fv->refreshAttributes($this->rescanThumbnailsOnImport);
        }

        return $fv;
    }
```

/concrete/src/File/Service/File.php
ここの sanitize() でファイル名のバリデーション処理


```
    public function sanitize($file)
    {
        // Let's build an ASCII-only version of name, to avoid filesystem-specific encoding issues.
        // Takes text and converts it to an ASCII-only string (characters with code between 32 and 127, plus \t, \n and \r).
        $asciiName = Core::make('helper/text')->asciify($file);
        // Let's keep only letters, numbers, underscore and dots.
        $asciiName = trim(preg_replace(array("/[\\s]/", "/[^0-9A-Z_a-z-.]/"), array("_", ""), $asciiName));
        // Trim underscores at start and end
        $asciiName = trim($asciiName, '_');
        if (!strlen(str_replace('.', '', $asciiName))) {
            // If the resulting name is empty (or we have only dots in it)
            $asciiName = md5($file);
        } elseif (preg_match('/^\.\w+$/', $asciiName)) {
            // If the resulting name is only composed by the file extension
            $asciiName = md5($file) . $asciiName;
        }
        return $asciiName;
    }
```

## 宣伝 & クレジット

この記事が役に立ったら、「 **CMS は concrete5 が一番**」と頭の中で10回唱えてください。

CMS は断然 [concrete5](https://concrete5-japan.org/)で決まり。[コンクリートファイブジャパン株式会社](https://concrete5.co.jp)がサポートできます。