pax_global_header 0000666 0000000 0000000 00000000064 15213763722 0014522 g ustar 00root root 0000000 0000000 52 comment=2e2af08157c66cbbc76539ccbd8869097a0c8feb
expressjs-multer-2e2af08/ 0000775 0000000 0000000 00000000000 15213763722 0015467 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/.github/ 0000775 0000000 0000000 00000000000 15213763722 0017027 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/.github/dependabot.yml 0000664 0000000 0000000 00000000504 15213763722 0021656 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
- package-ecosystem: npm
directory: /
schedule:
interval: monthly
open-pull-requests-limit: 10
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]
expressjs-multer-2e2af08/.github/workflows/ 0000775 0000000 0000000 00000000000 15213763722 0021064 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/.github/workflows/ci.yml 0000664 0000000 0000000 00000010534 15213763722 0022205 0 ustar 00root root 0000000 0000000 name: ci
on:
- pull_request
- push
permissions:
contents: read
jobs:
test:
permissions:
checks: write # for coverallsapp/github-action to create new checks
contents: read # for actions/checkout to fetch code
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
name:
- Node.js 10.x
- Node.js 11.x
- Node.js 12.x
- Node.js 13.x
- Node.js 14.x
- Node.js 15.x
- Node.js 16.x
- Node.js 17.x
- Node.js 18.x
- Node.js 19.x
- Node.js 20.x
- Node.js 21.x
- Node.js 22.x
- Node.js 23.x
- Node.js 24.x
- Node.js 25.x
- Node.js 26.x
include:
- name: Node.js 10.x
node-version: "10.24"
npm-i: mocha@8.4.0
- name: Node.js 11.x
node-version: "11.15"
npm-i: mocha@8.4.0
- name: Node.js 12.x
node-version: "12.22"
npm-i: mocha@9.2.2
- name: Node.js 13.x
node-version: "13.14"
npm-i: mocha@9.2.2
- name: Node.js 14.x
node-version: "14.21"
npm-i: mocha@9.2.2
- name: Node.js 15.x
node-version: "15.14"
npm-i: mocha@9.2.2
- name: Node.js 16.x
node-version: "16.20"
- name: Node.js 17.x
node-version: "17.9"
- name: Node.js 18.x
node-version: "18.18"
- name: Node.js 19.x
node-version: "19.9"
- name: Node.js 20.x
node-version: "20.9"
- name: Node.js 21.x
node-version: "21"
- name: Node.js 22.x
node-version: "22"
- name: Node.js 23.x
node-version: "23"
- name: Node.js 24.x
node-version: "24"
- name: Node.js 25.x
node-version: "25"
- name: Node.js 26.x
node-version: "26"
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Install Node.js ${{ matrix.node-version }}
shell: bash -eo pipefail -l {0}
run: |
nvm install --default ${{ matrix.node-version }}
if [[ "${{ matrix.node-version }}" == 0.* && "$(cut -d. -f2 <<< "${{ matrix.node-version }}")" -lt 10 ]]; then
nvm install --alias=npm 0.10
nvm use ${{ matrix.node-version }}
if [[ "$(npm -v)" == 1.1.* ]]; then
nvm exec npm npm install -g npm@1.1
ln -fs "$(which npm)" "$(dirname "$(nvm which npm)")/npm"
else
sed -i '1s;^.*$;'"$(printf '#!%q' "$(nvm which npm)")"';' "$(readlink -f "$(which npm)")"
fi
npm config set strict-ssl false
fi
dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH"
- name: Remove npm module(s) ${{ matrix.npm-rm }}
run: npm rm --silent --save-dev ${{ matrix.npm-rm }}
if: matrix.npm-rm != ''
- name: Install npm module(s) ${{ matrix.npm-i }}
run: npm install --save-dev ${{ matrix.npm-i }}
if: matrix.npm-i != ''
- name: Install Node.js dependencies
run: npm install
- name: List environment
id: list_env
shell: bash
run: |
echo "node@$(node -v)"
echo "npm@$(npm -v)"
npm -s ls ||:
(npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT"
- name: Lint code
run: npm run lint
- name: Run tests
shell: bash
run: |
if npm -ps ls nyc | grep -q nyc; then
npm run test-ci
else
npm test
fi
- name: Collect code coverage
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # master
if: steps.list_env.outputs.nyc != ''
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: run-${{ matrix.test_number }}
parallel: true
coverage:
permissions:
checks: write # for coverallsapp/github-action to create new checks
needs: test
runs-on: ubuntu-latest
steps:
- name: Upload code coverage
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
expressjs-multer-2e2af08/.github/workflows/codeql.yml 0000664 0000000 0000000 00000004655 15213763722 0023070 0 ustar 00root root 0000000 0000000 # For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: ["main", "v2"]
pull_request:
# The branches below must be a subset of the branches above
branches: ["main", "v2"]
schedule:
- cron: "0 0 * * 1"
permissions:
contents: read
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1
with:
languages: javascript
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# - name: Autobuild
# uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
# ℹ� Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1
with:
category: "/language:javascript"
expressjs-multer-2e2af08/.github/workflows/scorecard.yml 0000664 0000000 0000000 00000005657 15213763722 0023571 0 ustar 00root root 0000000 0000000 # This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '16 21 * * 1'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1
with:
sarif_file: results.sarif
expressjs-multer-2e2af08/.gitignore 0000664 0000000 0000000 00000000260 15213763722 0017455 0 ustar 00root root 0000000 0000000 # OS X
.DS_Store*
Icon?
._*
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Linux
.directory
*~
# npm
node_modules
*.log
*.gz
# Coverage & Test Output
coverage
.nyc_output
expressjs-multer-2e2af08/.npmrc 0000664 0000000 0000000 00000000023 15213763722 0016602 0 ustar 00root root 0000000 0000000 package-lock=false
expressjs-multer-2e2af08/CHANGELOG.md 0000664 0000000 0000000 00000010420 15213763722 0017275 0 ustar 00root root 0000000 0000000 # Change log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 2.2.0
- Fix [CVE-2026-5038](https://www.cve.org/CVERecord?id=CVE-2026-5038) ([GHSA-3p4h-7m6x-2hcm](https://github.com/expressjs/multer/security/advisories/GHSA-3p4h-7m6x-2hcm))
- Fix [CVE-2026-5079](https://www.cve.org/CVERecord?id=CVE-2026-5079) ([GHSA-72gw-mp4g-v24j](https://github.com/expressjs/multer/security/advisories/GHSA-72gw-mp4g-v24j))
## 2.1.1
- Fix [CVE-2026-3520](https://www.cve.org/CVERecord?id=CVE-2026-3520) ([GHSA-5528-5vmv-3xc2](https://github.com/expressjs/multer/security/advisories/GHSA-5528-5vmv-3xc2))
- fix error/abort handling
## 2.1.0
- Add `defParamCharset` option for UTF-8 filename support ([#1210](https://github.com/expressjs/multer/pull/1210))
- Fix [CVE-2026-2359](https://www.cve.org/CVERecord?id=CVE-2026-2359) ([GHSA-v52c-386h-88mc](https://github.com/expressjs/multer/security/advisories/GHSA-v52c-386h-88mc))
- Fix [CVE-2026-3304](https://www.cve.org/CVERecord?id=CVE-2026-3304) ([GHSA-xf7r-hgr6-v32p](https://github.com/expressjs/multer/security/advisories/GHSA-xf7r-hgr6-v32p))
## 2.0.2
- Fix [CVE-2025-7338](https://www.cve.org/CVERecord?id=CVE-2025-7338) ([GHSA-fjgf-rc76-4x9p](https://github.com/expressjs/multer/security/advisories/GHSA-fjgf-rc76-4x9p))
## 2.0.1
- Fix [CVE-2025-48997](https://www.cve.org/CVERecord?id=CVE-2025-48997) ([GHSA-g5hg-p3ph-g8qg](https://github.com/expressjs/multer/security/advisories/GHSA-g5hg-p3ph-g8qg))
## 2.0.0
- **Breaking change: The minimum supported Node version is now 10.16.0**
- Fix [CVE-2025-47935](https://www.cve.org/CVERecord?id=CVE-2025-47935) ([GHSA-44fp-w29j-9vj5](https://github.com/expressjs/multer/security/advisories/GHSA-44fp-w29j-9vj5))
- Fix [CVE-2025-47944](https://www.cve.org/CVERecord?id=CVE-2025-47944) ([GHSA-4pg4-qvpc-4q3h](https://github.com/expressjs/multer/security/advisories/GHSA-4pg4-qvpc-4q3h))
## 1.4.5-lts.2
- Fix out-of-band error event from busboy (#1177)
## 1.4.5-lts.1
- No changes
## 1.4.4-lts.1
- Bugfix: Bump busboy to fix CVE-2022-24434 (#1097)
- Breaking: Require Node.js 10.16.0 or later (#1097)
## 1.4.4 - 2021-12-07
- Bugfix: Handle missing field names (#913)
- Docs: Add Vietnamese translation (#803)
- Docs: Improve Spanish translation (#948)
## 1.4.3 - 2021-08-09
- Bugfix: Avoid deprecated pseudoRandomBytes function (#774)
- Docs: Add Português Brazil translation for README (#758)
- Docs: Clarify the callback calling convention (#775)
- Docs: Add example on how to link to html multipart form (#580)
- Docs: Add Spanish translation for README (#838)
- Docs: Add Math.random() to storage filename example (#841)
- Docs: Fix mistakes in russian doc (#869)
- Docs: Improve Português Brazil translation (#877)
- Docs: Update var to const in all Readmes (#1024)
- Internal: Bump mkdirp version (#862)
- Internal: Bump Standard version (#878)
## 1.4.2 - 2019-07-16
- Docs: Add Russian translation for README (#662)
- Docs: Patch zh-CN README base on newest README (#670)
- Docs: Fix broken link in Readme (#679)
- Docs: Fix broken link in Chinese Readme (#730)
- Docs: Fix typo in Russian README (#738)
- Docs: Add unit for fieldSize in busboy limit params (#734)
- Internal: Make unit tests comaptible with Node.js 13.x (#752)
## 1.4.1 - 2018-10-11
- Bugfix: Make sure that req.file.buffer always is a Buffer
## 1.4.0 - 2018-09-26
- Feature: Make Multer errors inherit from MulterError
## 1.3.1 - 2018-06-28
- Bugfix: Bump vulnerable dependency
## 1.3.0 - 2017-01-25
- Feature: Expose preservePath option
## 1.2.1 - 2016-12-14
- Bugfix: Prevent Multiple Errors from Crashing
## 1.2.0 - 2016-08-04
- Feature: add .none() for accepting only fields
## 1.1.0 - 2015-10-23
- Feature: accept any file, regardless of fieldname
## 1.0.6 - 2015-10-03
- Bugfix: always report limit errors
## 1.0.5 - 2015-09-19
- Bugfix: drain the stream before considering request done
## 1.0.4 - 2015-09-19
- Bugfix: propagate all errors from busboy
## 1.0.3 - 2015-08-06
- Bugfix: ensure file order is correct
## 1.0.2 - 2015-08-06
- Bugfix: don't hang when hitting size limit
## 1.0.1 - 2015-07-20
- Bugfix: decrement pending writes on error
## 1.0.0 - 2015-07-18
- Introduce storage engines
- Specify expected fields
- Follow the W3C JSON form spec
expressjs-multer-2e2af08/LICENSE 0000664 0000000 0000000 00000002131 15213763722 0016471 0 ustar 00root root 0000000 0000000 Copyright (c) 2014 Hage Yaapa <[http://www.hacksparrow.com](http://www.hacksparrow.com)>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
expressjs-multer-2e2af08/README.md 0000664 0000000 0000000 00000033521 15213763722 0016752 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer is a node.js middleware for handling `multipart/form-data`, which is primarily used for uploading files. It is written
on top of [busboy](https://github.com/mscdex/busboy) for maximum efficiency.
**NOTE**: Multer will not process any form which is not multipart (`multipart/form-data`).
## Translations
This README is also available in other languages:
| | |
| ------------------------------------------------------------------------------ | --------------- |
| [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) | Arabic |
| [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) | Chinese |
| [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) | French |
| [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) | Korean |
| [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) | Portuguese (BR) |
| [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) | Russian |
| [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) | Spanish |
| [O'zbek tili](https://github.com/expressjs/multer/blob/main/doc/README-uz.md) | Uzbek |
| [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) | Vietnamese |
| [Türkçe](https://github.com/expressjs/multer/blob/main/doc/README-tr.md) | Turkish |
## Installation
```sh
$ npm install multer
```
## Usage
Multer adds a `body` object and a `file` or `files` object to the `request` object. The `body` object contains the values of the text fields of the form, the `file` or `files` object contains the files uploaded via the form.
Basic usage example:
Don't forget the `enctype="multipart/form-data"` in your form.
```html
تعتبر Multer وسيط node.js لمعالجة `multipart/form-data`, والتي تÙ�ستخدم أساسًا لتØÙ…يل الملÙ�ات. تم بناء هذا الوسيط بالإعتماد على [busboy](https://github.com/mscdex/busboy) لأجل Ø§Ù„ØØµÙˆÙ„ على أقصى قدر من الكÙ�اءة.
**Ù…Ù„Ø§ØØ¸Ø©**: لن يقوم Multer بمعالجة أي شكل غير متعدد الأجزاء (`multipart/form-data`).
## الترجمات
هذا الملÙ� Ù…ØªØ§Ø Ø£ÙŠØ¶Ù‹Ø§ بلغات أخرى:
- [English](https://github.com/expressjs/multer/blob/main/README.md) (الإنجليزية)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (الإسبانية)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (الصينية)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (الكورية)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (الروسية)
- [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) (ال�تنامية)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (البرتغالية)
## التنصيب
```sh
$ npm install --save multer
```
## الاستعمال
يضيÙ� Multer كائن `body` وكائن `file` أو `files` إلى كائن `request`. ÙŠØØªÙˆÙŠ Ø§Ù„ÙƒØ§Ø¦Ù† `body` على قيم مدخلات النص Ù�ÙŠ الإستمارة ØŒ بينما ÙŠØØªÙˆÙŠ Ø§Ù„ÙƒØ§Ø¦Ù† `file` أو `files` على الملÙ�ات التي تم تØÙ…يلها عبر الإستمارة.
مثال على الاستخدام الأساسي:
لا تنسَ
`enctype="multipart/form-data"` �ي الإستمارة الخاص بك.
```html
```
```javascript
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
var uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
```
إذا Ø§ØØªØ¬Øª لمعالجة إستمارة متعددة الأجزاء للنص Ù�قط ØŒ Ù�يجب عليك استخدام الدالة `.none ()`:
```javascript
var express = require('express')
var app = express()
var multer = require('multer')
var upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contains the text fields
})
```
## واجهة برمجة التطبيقات (API)
### معلومات المل�
كل ملÙ� ÙŠØØªÙˆÙŠ Ø¹Ù„Ù‰ المعلومات التالية:
Ù…Ù�ØªØ§Ø | وصÙ� | Ù…Ù„Ø§ØØ¸Ø©
--- | --- | ---
`fieldname` | اسم المÙ�دخَل Ø§Ù„Ù…ØØ¯Ø¯ Ù�ÙŠ الإستمارة |
`originalname` | اسم المل� على كمبيوتر المستخدم |
`encoding` | نوع تش�ير المل� |
`mimetype` | نوع ملÙ� ملØÙ‚ات بريد إنترنت متعددة الأغراض ( MIME ) |
`size` | ØØ¬Ù… الملÙ� بالبايت |
`destination` | المجلد الذي تم ØÙ�ظ الملÙ� إليه | `تخزين على الاسطوانة` (`DiskStorage`)
`filename` | اسم المل� داخل "الوجهة" ( `destination` ) | `تخزين على الاسطوانة` (`DiskStorage`)
`path` | المسار الكامل للملÙ� الذي تم تØÙ…يله | `تخزين على الاسطوانة` (`DiskStorage`)
`buffer` | "ذاكرة" (`Buffer`) للمل� بأكمله | `تخزين على الذاكرة ` (`MemoryStorage`)
### `multer(opts)`
يقبل Multer كائن الخيارات ØŒ وأهمها خاصية `dest`ØŒ والتي ØªØØ¯Ø¯ مكان تØÙ…يل الملÙ�ات. Ù�ÙŠ ØØ§Ù„ ØØ°Ù�ت كائن الخيارات ØŒ سيتم Ø§Ù„Ø§ØØªÙ�اظ بالملÙ�ات Ù�ÙŠ الذاكرة ولن تتم كتابتها مطلقًا على القرص.
بشكل اÙ�تراضي ØŒ سيقوم Multer بإعادة تسمية الملÙ�ات لتجنب تعارض الأسماء. يمكن تخصيص وظيÙ�Ø© إعادة التسمية ÙˆÙ�قا Ù„Ø§ØØªÙŠØ§Ø¬Ø§ØªÙƒ.
�يما يلي الخيارات التي يمكن تمريرها إلى Multer:
Ù…Ù�ØªØ§Ø | وصÙ�
--- | ---
`dest` أو `storage` | مكان لتخزين المل�ات
`fileFilter` | دالة للسيطرة على المل�ات التي يتم قبولها
`limits` | ØØ¯ÙˆØ¯ البيانات التي تم تØÙ…يلها
`preservePath` | Ø§Ù„Ø§ØØªÙ�ظ بالمسار الكامل للملÙ�ات بدلاً من الاسم الأساسي
`defParamCharset` | مجموعة Ø§Ù„Ø£ØØ±Ù� الاÙ�تراضية لاستخدامها لقيم معاملات رأس الجزء (مثل اسم الملÙ�) التي ليست معاملات موسعة (لا ØªØØªÙˆÙŠ Ø¹Ù„Ù‰ مجموعة Ø£ØØ±Ù� ØµØ±ÙŠØØ©). الاÙ�تراضي: `'latin1'`
Ù�ÙŠ تطبيق ويب متوسط ​​، قد تكون هناك ØØ§Ø¬Ø© Ù�قط إلى `dest`ØŒ وتكوينها كما هو Ù…ÙˆØ¶Ø Ù�ÙŠ
المثال التالي :
```javascript
var upload = multer({ dest: 'uploads/' })
```
إذا كنت تريد مزيدًا من التØÙƒÙ… Ù�ÙŠ عمليات التØÙ…يل ØŒ Ù�Ø³ØªØØªØ§Ø¬ إلى استخدام خيار `storage` بدلاً من `dest`. يأتي Multer مع Ù…ØØ±ÙƒØ§Øª التخزين `DiskStorage` Ùˆ` MemoryStorage` Ø› كما تتوÙ�ر المزيد من Ø§Ù„Ù…ØØ±ÙƒØ§Øª من أطراÙ� ثالثة.
#### `.single(fieldname)`
قبول ملÙ� ÙˆØ§ØØ¯ باسم `اسم-المÙ�دخَل`. سيتم تخزين الملÙ� Ù�ÙŠ `req.file`.
#### `.array(fieldname[, maxCount])`
قبول مصÙ�ÙˆÙ�Ø© من الملÙ�ات ØŒ وكلها تØÙ…Ù„ اسم `اسم-المÙ�دخَل`. يظهر خطأ اختياريً إذا تم تØÙ…يل ملÙ�ات أكثر من `maxCount`. سيتم تخزين مصÙ�ÙˆÙ�Ø© الملÙ�ات Ù�ÙŠ `req.files`.
#### `.fields(fields)`
قبول مزيج من الملÙ�ات ØŒ Ø§Ù„Ù…ØØ¯Ø¯ بواسطة `المدخلات`. سيتم تخزين كائن مع مصÙ�ÙˆÙ�ات من الملÙ�ات Ù�ÙŠ `req.files`.
يجب أن تكون `المدخلات` عبارة عن مص�و�ة من الكائنات التي تو�ر بشكل اساسي `name` واختيارياً `maxCount`.
مثال:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
قبول المدخلات النصية Ù�قط. Ù�ÙŠ ØØ§Ù„Ø© رÙ�ع أي ملÙ� ØŒ سيتم إصدار خطأ بشيÙ�رة "LIMIT \_UNEXPECTED \_FILE".
#### `.any()`
قبول جميع المل�ات التي تأتي عبر السلك. سيتم تخزين مص�و�ة من المل�ات �ي `req.files`.
**ØªØØ°ÙŠØ±:** تأكد من أنك تعالج دائمًا الملÙ�ات التي يقوم المستخدم بتØÙ…يلها. لا تقم أبداً بإضاÙ�Ø© multer باعتبارها أداة وسيطة عامة ØŒ ØÙŠØ« يمكن للمستخدم الضار تØÙ…يل الملÙ�ات إلى مسار غير متتوقع. استخدم هذه الدالة Ù�قط على المسارات التي تتعامل Ù�يها مع الملÙ�ات التي تم تØÙ…يلها.
### `storage`
#### `DiskStorage`
يمنØÙƒ Ù…ØØ±Ùƒ تخزين القرص التØÙƒÙ… الكامل Ù�ÙŠ تخزين الملÙ�ات على القرص.
```javascript
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
```
هناك خياران Ù…ØªØ§ØØ§Ù† ØŒ `destination` Ùˆ `filename`. كلاهما يعملان على ØªØØ¯ÙŠØ¯ مكان تخزين الملÙ�.
يتم استخدام `destination` Ù„ØªØØ¯ÙŠØ¯ أي مجلد يجب تخزين الملÙ�ات المØÙ…لة. يمكن أيضًا إعطاء هذا كـ`سلسلة` (مثل `'/tmp/uploads'`). إذا لم يتم إعطاء `destination` ØŒ Ù�سيتم استخدام الدليل الاÙ�تراضي لنظام التشغيل للملÙ�ات المؤقتة.
**Ù…Ù„Ø§ØØ¸Ø©:** أنت مسؤول عن إنشاء الدليل عند توÙ�ر `destination` كدالة. عند المرور بسلسلة ØŒ سوÙ� يتأكد multer من إنشاء الدليل من أجلك.
يتم استخدام `اسم الملÙ�` Ù„ØªØØ¯ÙŠØ¯ ما يجب تسمية الملÙ� داخل المجلد. إذا لم يتم تقديم `اسم الملÙ�`ØŒ Ù�سيتم إعطاء كل ملÙ� اسمًا عشوائيًا لا يتضمن أي امتداد للملÙ�.
**Ù…Ù„Ø§ØØ¸Ø©:** لن يقوم multer Ø¨Ø¥Ù„ØØ§Ù‚ اي ملØÙ‚ ملÙ� لك، الدالة الخاص بك يجب أن تقوم بإرجاع اسم ملÙ� كامل بملØÙ‚ الملÙ�.
يتم تمرير كل دالة من خلال الطلب (req`) وبعض المعلومات ØÙˆÙ„ الملÙ� (`file`) للمساعدة Ù�ÙŠ اتخاذ القرار.
Ù„Ø§ØØ¸ أن `req.body` ربما لم يتم ملؤها بالكامل بعد. يعتمد ذلك على الترتيب الذي يقوم به العميل من خلال نقل المدخلات والملÙ�ات إلى الخادم.
#### `MemoryStorage`
يخزن Ù…ØØ±Ùƒ تخزين الذاكرة الملÙ�ات الموجودة Ù�ÙŠ الذاكرة ككائنات `ذاكرة` (`Buffer`). ليس لديها أي خيارات.
```javascript
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })
```
عند استخدام ذاكرة التخزين ØŒ Ø³ØªØØªÙˆÙŠ Ù…Ø¹Ù„ÙˆÙ…Ø§Øª الملÙ� على Ù…Ù�دخَل يسمى `buffer` الذي ÙŠØØªÙˆÙŠ Ø¹Ù„Ù‰ الملÙ� بأكمله.
**ØªØØ°ÙŠØ±**: يمكن أن يؤدي تØÙ…يل ملÙ�ات كبيرة جدًا أو ملÙ�ات صغيرة نسبيًا بأعداد كبيرة Ùˆ بسرعة كبيرة إلى Ù†Ù�اد ذاكرة التطبيق عند استخدام ذاكرة التخزين.
### `limits`
كائن ÙŠØØ¯Ø¯ ØØ¯ÙˆØ¯ ØØ¬Ù… الخصائص الاختيارية التالية. يقوم Multer بتمرير هذا الكائن إلى busboy مباشرة ØŒ ويمكن العثور على تÙ�اصيل الخصائص من خلال [صÙ�ØØ© busboy's](https://github.com/mscdex/busboy#busboy-methods).
تتوÙ�ر القيم الصØÙŠØØ© التالية:
Ù…Ù�ØªØ§Ø | وصÙ� | اÙ�تراضي
--- | --- | ---
`fieldNameSize` | Ø§Ù„ØØ¯ الأقصى Ù„ØØ¬Ù… اسم المÙ�دخَل | 100 بايت
`fieldSize` | Ø§Ù„ØØ¯ الأقصى Ù„ØØ¬Ù… قيمة المÙ�دخَل (بالبايت) | 1 ميغابايت
`fields` | Ø§Ù„ØØ¯ الأقصى لعدد المدخلات التى لا تعتبر من الملÙ�ات | ما لا نهاية
`fileSize` | ØØ¬Ù… الملÙ� الأقصى بالنسبة لإستمارة متعددة الأجزاء (بالبايت) | ما لا نهاية
`files` | Ø§Ù„ØØ¯ الأقصى لعدد المدخلات من نوع الملÙ�ات بالنسبة لإستمارة متعددة الأجزاء | ما لا نهاية
`parts` | Ø§Ù„ØØ¯ الأقصى لعدد الأجزاء (مدخلات + ملÙ�ات) بالنسبة لإستمارة متعددة الأجزاء | ما لا نهاية
`headerPairs` | Ø§Ù„ØØ¯ الأقصى لعدد أزواج الرأس (المÙ�ØªØ§Ø => القيمة) المطلوب تØÙ„يلها بالنسبة لإستمارة متعددة الأجزاء | 2000
يمكن أن يساعد ØªØØ¯ÙŠØ¯ Ø§Ù„ØØ¯ÙˆØ¯ Ù�ÙŠ ØÙ…اية موقعك من هجمات ØØ¬Ø¨ الخدمة (DoS).
### `fileFilter`
اضبط هذا على دالة للتØÙƒÙ… Ù�ÙŠ الملÙ�ات التي ينبغي تØÙ…يلها وأي الملÙ�ات يجب تخطيها. يجب أن تبدو دالة كما يلي:
```javascript
function fileFilter (req, file, cb) {
// The function should call `cb` with a boolean
// to indicate if the file should be accepted
// To reject this file pass `false`, like so:
cb(null, false)
// To accept the file pass `true`, like so:
cb(null, true)
// You can always pass an error if something goes wrong:
cb(new Error('I don\'t have a clue!'))
}
```
## معالجة الأخطاء
عند مواجهة خطأ ، سيقوم Multer بت�ويض الخطأ إلى Express. يمكنك
عرض صÙ�ØØ© خطأ لطيÙ�Ø© باستخدام [طريقة Express القياسية](http://expressjs.com/guide/error-handling.html).
إذا كنت تريد إنتقاء الأخطاء ÙˆØ§Ù„ØØµÙˆÙ„ على [أخطاء Multer Ù�قط](https://github.com/expressjs/multer/blob/main/lib/multer-error.js)ØŒ Ù�يمكنك نداء بدالة الوسيطة من قبل Ù†Ù�سك. أيضًا ØŒ إذا كنت تريد التقاط أخطاء Multer Ù�قط ØŒ Ù�يمكنك استخدام صنÙ� `MulterError` المتصل بالكائن` multer` Ù†Ù�سه (على سبيل المثال `err instanceof multer.MulterError`).
```javascript
var multer = require('multer')
var upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading.
} else if (err) {
// An unknown error occurred when uploading.
}
// Everything went fine.
})
})
```
## Ù…ØØ±Ùƒ التخزين الخاص بك
Ù„Ù„ØØµÙˆÙ„ على معلومات ØÙˆÙ„ كيÙ�ية إنشاء Ù…ØØ±Ùƒ التخزين الخاص بك ØŒ راجع [Ù…ØØ±Ùƒ تخزين Multer](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## الترخيص
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-es.md 0000664 0000000 0000000 00000034112 15213763722 0020121 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer es un "*middleware*" de node.js para el manejo de `multipart/form-data`, el cuál es usado sobre todo para la subida de archivos. Está escrito sobre [busboy](https://github.com/mscdex/busboy) para maximizar su eficiencia.
**NOTA**: Multer no procesará ningún formulario que no sea multiparte (`multipart/form-data`).
## Traducciones
Éste archivo README también está disponible en otros lenguajes:
- [English](https://github.com/expressjs/multer/blob/main/README.md) (Inglés)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (Chino)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (Coreano)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (Ruso)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (Portugués Brasileño)
## Instalación
```sh
$ npm install --save multer
```
## Uso
Multer añade un objeto `body` y un objeto `file` o `files` al objeto `request`. El objeto `body` contiene los valores correspondientes a los campos de texto del formulario, los objetos `file` o `files` contienen los archivos que serán subidos mediante el formulario.
Ejemplo básico de cómo usarlo:
No te olvides de `enctype="multipart/form-data"` en tu formulario.
```html
```
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file es el archivo del `avatar`
// req.body contendrá los campos de texto, si los hubiera.
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files es el arreglo (array) de archivos `photos`
// req.body contendrá los campos de texto, si los hubiera.
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files es un objeto (String -> Array) donde el nombre del campo es la clave (key) y el valor es el arreglo (array) de archivos
//
// Ejemplo
// req.files['avatar'][0] -> Archivo
// req.files['gallery'] -> Array
//
// req.body contendrá los campos de texto, si los hubiera.
})
```
En caso de que necesites manejar un formulario multiparte (multipart form) que sólo contiene campos de texto, deberias usar el método `.none()`:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contiene los campos textuales
})
```
Este es un ejemplo de cómo se utiliza multer en un formulario HTML. Presta especial atención en los campos `enctype="multipart/form-data"` y `name="uploaded_file"`:
```html
```
Luego en tu archivo javascript agrega estas lÃneas para acceder tanto al archivo (file) como al body.Es importante que uses el valor del campo `name` del formulario, en tu función de subida. Esto le indica a multer en qué campo de la petición debe buscar los archivos. Si estos campos no son los mismos en el formulario HTML y en tu servidor, la subida fallará:
```javascript
const multer = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.file es el nombre de tu archivo en el formulario anterior, en este caso 'uploaded_file'
// req.body contendrá los campos de texto, si los hubiera.
console.log(req.file, req.body)
});
```
## API
### Información del archivo
Cada archivo contiene la siguiente información:
Clave (Key) | Descripción | Nota
--- | --- | ---
`fieldname` | Nombre del campo especificado en el formulario |
`originalname` | Nombre del archivo en la computadora del usuario |
`encoding` | Tipo de codificación del archivo |
`mimetype` | Mime type del archivo |
`size` | Tamaño del archivo en Bytes |
`destination` | La carpeta donde se guardó el archivo | `DiskStorage`
`filename` | El nombre del archivo en `destination` | `DiskStorage`
`path` | La ruta completa al archivo subido | `DiskStorage`
`buffer` | Un `Buffer` del archivo completo | `MemoryStorage`
### `multer(opts)`
Multer acepta un objeto para configurar sus opciones, la más básica de ellas es la propiedad `dest`, la cual informa a Multer dónde debe subir los archivos. En caso de que omitas el objeto con las opciones, los archivos serán guardados en la memoria y nunca serán escritos en el disco.
Por defecto, Multer renombrará los archivos para evitar conflictos de nombres. La función usada para renombrarlos puede ser modificada acorde a tus necesidades.
Las siguientes son las opciones que pueden ser utilizadas con Multer.
Clave (key) | Descripción
--- | ---
`dest` o `storage` | Donde se guardarán los archivos
`fileFilter` | Función para controlar qué archivos son aceptados
`limits` | LÃmites de los datos subidos
`preservePath` | Mantiene la ruta completa de la ubicación de los archivos, en vez de sólo sus nombres
`defParamCharset` | Conjunto de caracteres por defecto para usar en valores de parámetros de encabezados de partes (ej. nombre de archivo) que no son parámetros extendidos (que contienen un conjunto de caracteres explÃcito). Por defecto: `'latin1'`
En la aplicación web promedio es probable que sólo se requiera `dest`, siendo configurado como en el siguiente ejemplo:
```javascript
const upload = multer({ dest: 'uploads/' })
```
Si quieres más control sobre tus subidas, tendrás que usar la opción `storage` en vez de `dest`. Multer incorpora los mecanismos de almacenamiento `DiskStorage` y `MemoryStorage`; existen otros medios provistos por terceros.
#### `.single(fieldname)`
Acepta un único archivo con el nombre `fieldname`. Dicho archivo será guardado en `req.file`.
#### `.array(fieldname[, maxCount])`
Acepta un arreglo (array), de archivos, todos con el nombre `fieldname`. Opcionalmente puede generarse un error si se intentan subir una cantidad de archivos superior a `maxCount`. El arreglo (array) de archivos será guardado en `req.files`.
#### `.fields(fields)`
Acepta una mezcla de archivos, especificados por `field`. Un objeto con arreglos (arrays) de archivos será guardado en `req.files`
`fields` deberÃa ser un arreglo (array) de objetos con `name` y opcionalmente `maxCount`.
Ejemplo:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
Acepta sólo campos de texto. En caso de intentar subir un archivo, se generará un error con el siguiente código
"LIMIT\_UNEXPECTED\_FILE".
#### `.any()`
Acepta todos los archivos que han sido enviados. Un arreglo (array) conteniendo los archivos, será guardado en `req.files`.
**ADVERTENCIA:** Asegúrate de siempre manejar los archivos que los usuarios intenten subir. Nunca uses Multer como una función middleware de manera global dado que, de esta forma, un usuario malicioso podrÃa subir archivos por medio de rutas que no has anticipado. Usa sólo esta función en rutas en las que estás esperando archivos.
### `storage`
#### `DiskStorage`
El motor de almacenamiento en disco te ofrece un control total sobre el almacenamiento de archivos en tu disco.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
Hay dos opciones disponibles, `destination` y `filename`. Ambas son funciones que determinan dónde deberÃa almacenarse el archivo.
`destination` se utiliza para determinar en qué carpeta se almacenarán los archivos subidos. Tambien se puede proporcionar como un `string` (por ejemplo: `'/tmp/uploads'`). Si no se proporciona `destination`, se utilizara el directorio predeterminado del sistema operativo para archivos temporales.
**Nota:** Al pasar `destination` como una función, tú eres el responsable de crear los directorios donde los archivos serán almacenados. Cuando asignas un `string` a `destination`, Multer se asegurará de que el directorio sea creado en caso de no encontrarlo.
`filename` es usado para determinar cómo deberÃa ser nombrado el archivo dentro de la carpeta. Si `filename` no es provisto, a cada archivo se le asignará un nombre aleatorio que no incluirá ninguna extensión.
**Nota:** Multer no añadirá ningúna extensión de archivos por ti, es tu función la que deberÃa retornar un nombre completo, que incluya también la extensión del archivo.
El objeto petición (`req`) y parte de la información del archivo (`file`) son pasadas a tu función para ayudar con la decisión en la nomenclatura.
Nota que `req.body` puede que no haya sido totalmente poblado todavÃa. Esto depende del orden en el que el cliente transmita sus campos y archivos hacia el servidor.
Para comprender la convención de llamada utilizada en el callback (necesitas pasar null como primer parametro), consulta en
[Node.js manejo de errores](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors)
#### `MemoryStorage`
El motor de almacenamiento en memoria almacena los archivos en memoria como objetos `Buffer`. Para esto no se proveen opciones.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
Al usar el almacenamiento en memoria, la información del archivo contendrá un campo llamado `buffer` que contiene el archivo entero.
**ADVERTENCIA**: Subir archivos grandes, o relativamente pequeños pero en gran cantidad y muy rápido, puede provocar que tu aplicación se quede sin memoria cuando es usado el almacenamiento en memoria.
### `limits`
Un objeto especifica los lÃmites correpondientes a los tamaños de las siguientes propiedades opcionales. Multer pasa este objeto directamente a *busboy*, los detalles de las propiedades pueden encontrarse en [la página de busboy](https://github.com/mscdex/busboy#busboy-methods).
Los siguientes valores en números enteros están disponibles:
Clave (Key) | Descripción | Por defecto
--- | --- | ---
`fieldNameSize` | Tamaño máximo del nombre del campo | 100 bytes
`fieldSize` | Tamaño máximo de los valores para cada campo (en bytes) | 1MB
`fields` | Número máximo de campos que no son archivos | Infinito
`fileSize` | Para formularios multiparte, el tamaño máximo de los archivos (en bytes) | Infinito
`files` | Para los formularios multiparte, el número máximo de campos para archivos | Infinito
`parts` | Para los formularios multiparte, el número máximo de partes (campos + archivos) | Infinito
`headerPairs` | Para los formularios multiparte, el número máximo de cabeceras de pares clave=>valor para analizar | 2000
Especificar los lÃmites puede ayudarte a proteger tu sitio contra ataques de denegación del servicio (DoS).
### `fileFilter`
Asigna ésto a una función para controlar cuáles archivos deben ser subidos y cuáles deben ser omitidos. La función deberÃa verse como ésta:
```javascript
function fileFilter (req, file, cb) {
// La función debe llamar a `cb` usando una variable del tipo boolean
// para indicar si el archivo deberÃa ser aceptado o no
// Para rechazar el archivo es necesario pasar `false`, de la siguiente forma:
cb(null, false)
// Para aceptar el archivo es necesario pasar `true`, de la siguiente forma:
cb(null, true)
// Siempre puedes pasar un error en caso de que algo salga mal:
cb(new Error('No tengo la menor idea!'))
}
```
## Manejo de errores
Al encontrarse con un error, Multer delegará ese error a Express. Puedes mostrar una linda página de error usando [la manera standard de Express](http://expressjs.com/guide/error-handling.html).
Si quieres capturar los errores especÃficamente desde Multer, puedes llamar la función middleware tú mismo. También, si quieres capturar sólo [los errores de Multer](https://github.com/expressjs/multer/blob/main/lib/multer-error.js), puedes usar la clase `MulterError` que está adherida al mismo objeto `multer` (por ejemplo: `err instanceof multer.MulterError`).
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Un error de Multer ocurrió durante la subida.
} else if (err) {
// Un error desconocido ocurrió durante la subida.
}
// Todo salió bien.
})
})
```
## Mecanismos de almacenamiento personalizados
Para más información acerca de cómo construir tu propio mecanismo de almacenamiento, recomendamos leer [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## Licencia
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-fr.md 0000664 0000000 0000000 00000035246 15213763722 0020132 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer est un middleware node.js pour la gestion des données `multipart/form-data` qui est principalement utilisé pour télécharger des fichiers.
Il est écrit au-dessus de [busboy](https://github.com/mscdex/busboy) pour une efficacité maximale.
**NOTE**: Multer ne traitera aucun formulaire qui ne soit pas un multipart (`multipart/form-data`).
## Translations
This README is also available in other languages:
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (Arabe)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (Espagnol)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (Chinois)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (Coréen)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (Russe)
- [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) (Vietnamien)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (Portugais du Brésil)
- [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) (Français)
## Installation
```sh
$ npm install --save multer
```
## Usage
Multer ajoute un objet `body` et un objet `file` ou `files` à l'objet `request`. L'objet `body` contient les valeurs des champs texte du formulaire, l'objet `file` ou `files` contient les fichiers téléchargés via le formulaire.
Exemple d'utilisation de base :
N'oubliez pas le `enctype="multipart/form-data"` dans votre formulaire.
```html
```
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file est le fichier `avatar`
// req.body contiendra les champs de texte, s'il y en avait
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files est un tableau de fichiers "photos"
// req.body contiendra les champs de texte, s'il y en avait
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files est un objet (String -> Array) où fieldname est la clé et la valeur est un tableau de fichiers
//
// e.g.
// req.files['avatar'][0] -> Fichier
// req.files['gallery'] -> Tableau
//
// req.body contiendra les champs de texte, s'il y en avait
})
```
Dans le cas où vous auriez besoin de gérer un formulaire en plusieurs parties texte uniquement, vous devez utiliser la méthode `.none()`:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contiens les champs de text
})
```
Voici un exemple d'utilisation de multer dans un formulaire HTML. Faites particulièrement attention aux champs `enctype="multipart/form-data"` et `name="uploaded_file"`:
```html
```
Ensuite, dans votre fichier javascript, vous ajouterez ces lignes pour accéder à la fois au fichier et au corps. Il est important que vous utilisiez la valeur du champ `name` du formulaire dans votre fonction de téléchargement. Cela indique à Multer dans quel champ de la requête il doit rechercher les fichiers. Si ces champs ne sont pas les mêmes dans le formulaire HTML et sur votre serveur, votre téléchargement échouera:
```javascript
const multer = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.file est le nom de votre fichier dans le formulaire ci-dessus, ici 'uploaded_file'
// req.body contiendra les champs de texte, s'il y en avait
console.log(req.file, req.body)
});
```
## API
### Informations sur les fichiers
Chaque fichier contient les informations suivantes:
Clé | Description | Notes
--- |------------------------------------------------| ---
`fieldname` | Nom du champ spécifié dans le formulaire |
`originalname` | Nom du fichier sur l'ordinateur de l'utilisateur |
`encoding` | Type d'encodage du fichier |
`mimetype` | Type Mime du fichier |
`size` | Taille du fichier en octets |
`destination` | TLe dossier dans lequel le fichier a été enregistré | `DiskStorage`
`filename` | Le nom du fichier dans la `destination` | `DiskStorage`
`path` | Le chemin d'accès complet au fichier téléchargé | `DiskStorage`
`buffer` | Un `Buffer` du fichier entier | `MemoryStorage`
### `multer(opts)`
Multer accepte un objet d'options, dont le plus basique est le `dest`
propriété, qui indique à Multer où télécharger les fichiers. Au cas où vous omettez l'objet
options, les fichiers seront conservés en mémoire et ne seront jamais écrits sur le disque.
Par défaut, Multer renommera les fichiers afin d'éviter les conflits de nommage. Les
la fonction de renommage peut être personnalisée en fonction de vos besoins.
Voici les options qui peuvent être transmises à Multer.
Clé | Description
--- | ---
`dest` ou `storage` | Où stocker les fichiers
`fileFilter` | Fonction pour contrôler quels fichiers sont acceptés
`limits` | Limites des données téléchargées
`preservePath` | Conservez le chemin complet des fichiers au lieu du nom de base uniquement
`defParamCharset` | Jeu de caractères par défaut à utiliser pour les valeurs des paramètres d'en-tête de partie (par exemple, nom de fichier) qui ne sont pas des paramètres étendus (qui contiennent un jeu de caractères explicite). Par défaut : `'latin1'`
Dans une application Web moyenne, seul `dest` peut être requis et configuré comme indiqué dans
l'exemple suivant.
```javascript
const upload = multer({ dest: 'uploads/' })
```
Si vous voulez plus de contrôle sur vos téléchargements, vous voudrez utiliser le `storage`
option au lieu de `dest`. Multer est livré avec des moteurs de stockage `DiskStorage`
et `MemoryStorage`; D'autres moteurs sont disponibles auprès de tiers.
#### `.single(fieldname)`
Acceptez un seul fichier avec le nom `fieldname`. Le fichier unique sera stocké
dans `req.file`.
#### `.array(fieldname[, maxCount])`
Acceptez un tableau de fichiers, tous avec le nom `fieldname`. Eventuellement erreur si
plus de `maxCount` fichiers sont téléchargés. Le tableau de fichiers sera stocké dans
`req.files`.
#### `.fields(fields)`
Accepte un mélange de fichiers, spécifié par `fields`. Un objet avec des tableaux de fichiers
seront stockés dans `req.files`.
`fields` doit être un tableau d'objets avec `name` et éventuellement un `maxCount`.
Exemple:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
N'acceptez que les champs de texte. Si un téléchargement de fichier est effectué, une erreur avec le code
"LIMIT\_UNEXPECTED\_FILE" sera émis.
#### `.any()`
Accepte tous les fichiers qui arrivent sur le fil. Un tableau de fichiers sera stocké dans
`req.files`.
**ATTENTION:** Assurez-vous de toujours gérer les fichiers qu'un utilisateur télécharge.
N'ajoutez jamais multer en tant que middleware global car un utilisateur malveillant pourrait télécharger des
fichiers vers un itinéraire que vous n'aviez pas prévu. N'utilisez cette fonction que sur les itinéraires
où vous gérez les fichiers téléchargés.
### `storage`
#### `DiskStorage`
Le moteur de stockage sur disque vous donne un contrôle total sur le stockage des fichiers sur le disque.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
cb(null, file.fieldname + '-' + uniqueSuffix)
}
})
const upload = multer({ storage: storage })
```
Il y a deux options disponibles, `destination` et `filename`. Elles sont toutes les deux
des fonctions qui déterminent où le fichier doit être stocké.
`destination` est utilisé pour déterminer dans quel dossier les fichiers téléchargés doivent
être stocké. Cela peut également être donné sous forme de `string` (par exemple `'/tmp/uploads'`). Sinon
`destination` est donné, le répertoire par défaut du système d'exploitation est utilisé pour les
fichiers temporaires.
**Remarque:** Vous êtes responsable de la création du répertoire lorsque vous fournissez
`destination` en tant que fonction. Lors du passage d'une chaîne, multer s'assurera que
le répertoire est créé pour vous.
`filename` est utilisé pour déterminer le nom du fichier dans le dossier.
Si aucun "nom de fichier" n'est donné, chaque fichier recevra un nom aléatoire qui n'inclut
pas d'extension de fichier.
**Remarque:** Multer n'ajoutera aucune extension de fichier pour vous, votre fonction
doit renvoyer un nom de fichier complet avec une extension de fichier.
Chaque fonction reçoit à la fois la requête (`req`) et des informations sur
le dossier (`file`) pour aider à la décision.
Notez que `req.body` n'a peut-être pas encore été entièrement rempli. Cela dépend de l'ordre
où le client transmet les champs et les fichiers au serveur.
Pour comprendre la convention d'appel utilisée dans le rappel (nécessité de passer
null comme premier paramètre), reportez-vous Ã
[Node.js error handling](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors)
#### `MemoryStorage`
Le moteur de stockage en mémoire stocke les fichiers en mémoire en tant qu'objets `Buffer`. Il
n'a pas d'options.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
Lors de l'utilisation du stockage en mémoire, les informations sur le fichier contiendront un champ appelé
`buffer` qui contient le fichier entier.
**ATTENTION**: Le téléchargement de fichiers très volumineux ou de fichiers relativement petits en grand
nombres très rapidement, peut entraîner un manque de mémoire de votre application lorsque
le stockage en mémoire est utilisé.
### `limits`
Un objet spécifiant les limites de taille des propriétés facultatives suivantes. Multer passe directement cet objet dans busboy, et les détails des propriétés peuvent être trouvés sur [la page de busboy](https://github.com/mscdex/busboy#busboy-methods).
Les valeurs entières suivantes sont disponibles :
Clé | Description | Default
--- |---------------------------------------------------------------------------| ---
`fieldNameSize` | Taille maximale du nom de champ | 100 bytes
`fieldSize` | Max field value size (in bytes) | 1MB
`fields` | Taille maximale de la valeur du champ (en octets) | Infinity
`fileSize` | Pour les formulaires multipart, la taille maximale du fichier (en octets) | Infinity
`files` | Pour les formulaires multipart, le nombre maximal de champs de fichier | Infinity
`parts` | Pour les formulaires multipart, le nombre max de parties (champs + fichiers) | Infinity
`headerPairs` | Pour les formulaires multipart, le nombre maximum de paires clé=>valeur d'en-tête à analyser | 2000
Spécifier les limites peut aider à protéger votre site contre les attaques par déni de service (DoS).
### `fileFilter`
Définissez ceci sur une fonction pour contrôler quels fichiers doivent être téléchargés et lesquels
devrait être ignoré. La fonction devrait ressembler à ceci:
```javascript
function fileFilter (req, file, cb) {
// La fonction doit appeler `cb` avec un booléen
// pour indiquer si le fichier doit être accepté
// Pour rejeter ce fichier, passez `false`, comme ceci:
cb(null, false)
// Pour accepter le fichier, passez `true`, comme ceci:
cb(null, true)
// Vous pouvez toujours passer une erreur si quelque chose ne va pas:
cb(new Error('I don\'t have a clue!'))
}
```
## Gestion des Erreurs
En cas d'erreur, Multer déléguera l'erreur à Express. Vous pouvez
afficher une belle page d'erreur en utilisant [la voie express standard](http://expressjs.com/guide/error-handling.html).
Si vous souhaitez détecter les erreurs spécifiquement de Multer, vous pouvez appeler la
fonction middleware par vous-même. Aussi, si vous voulez attraper seulement [les erreurs Multer](https://github.com/expressjs/multer/blob/main/lib/multer-error.js), vous pouvez utiliser la classe `MulterError` qui est jointe à l'objet `multer` lui-même (par exemple `err instanceof multer.MulterError`).
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Une erreur Multer s'est produite lors du téléchargement.
} else if (err) {
// Une erreur inconnue s'est produite lors du téléchargement.
}
// Tout s'est bien passé.
})
})
```
## Moteur de stockage personnalisé
Pour plus d'informations sur la création de votre propre moteur de stockage, consultez [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## License
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-ko.md 0000664 0000000 0000000 00000030641 15213763722 0020126 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer는 파ì�¼ 업로드를 위해 사용ë�˜ëŠ” `multipart/form-data` 를 다루기 위한 node.js ì�˜ 미들웨어 입니다. 효율성ì�„ 최대화 하기 위해 [busboy](https://github.com/mscdex/busboy) 를 기반으로 í•˜ê³ ìžˆìŠµë‹ˆë‹¤.
**주**: Multer는 multipart (`multipart/form-data`)가 아닌 ��서는 �작하지 않습니다.
## 번ì—
ì�´ 문서는 아래ì�˜ 언어로ë�„ ì œê³µë�©ë‹ˆë‹¤:
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (아�비아 �)
- [English](https://github.com/expressjs/multer/blob/main/README.md) (�어)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (스페�어)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (중êµì–´)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (러시아)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (�르투갈어 BR)
## 설치
```sh
$ npm install --save multer
```
## 사용법
Multer는 `body` ê°�체와 한 ê°œì�˜ `file` 혹ì�€ 여러개ì�˜ `files` ê°�체를 `request` ê°�ì²´ì—� 추가합니다. `body` ê°�체는 í�¼ í…�스트 필드ì�˜ ê°’ì�„ í�¬í•¨í•˜ê³ , 한 ê°œ 혹ì�€ 여러개ì�˜ 파ì�¼ ê°�체는 í�¼ì�„ 통해 업로드ë�œ 파ì�¼ë“¤ì�„ í�¬í•¨í•˜ê³ 있습니다.
기본 사용 ì˜ˆì œ:
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file ì�€ `avatar` ë�¼ëŠ” 필드ì�˜ 파ì�¼ ì •ë³´ìž…ë‹ˆë‹¤.
// í…�스트 필드가 있는 경우, req.bodyê°€ ì�´ë¥¼ í�¬í•¨í• 것입니다.
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files 는 `photos` ë�¼ëŠ” 파ì�¼ì •보를 배열로 ê°€ì§€ê³ ìžˆìŠµë‹ˆë‹¤.
// í…�스트 필드가 있는 경우, req.bodyê°€ ì�´ë¥¼ í�¬í•¨í• 것입니다.
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files는 (String -> Array) 형태� �체 입니다.
// 필드명ì�€ ê°�ì²´ì�˜ keyì—�, 파ì�¼ ì •ë³´ëŠ” 배열로 valueì—� ì €ìž¥ë�©ë‹ˆë‹¤.
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// í…�스트 필드가 있는 경우, req.bodyê°€ ì�´ë¥¼ í�¬í•¨í• 것입니다.
})
```
í…�스트 ì „ìš© multipart í�¼ì�„ 처리해야 하는 경우, ì–´ë– í•œ multer 메소드 (`.single()`, `.array()`, `fields()`) ë�„ ì‚¬ìš©í• ìˆ˜ 있습니다. 아래는 `.array()` 를 사용한 ì˜ˆì œ 입니다 :
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.array(), function (req, res, next) {
// req.body는 �스트 필드를 �함합니다.
})
```
## API
### 파ì�¼ ì •ë³´
ê°�ê°�ì�˜ 파ì�¼ì�€ 아래ì�˜ ì •ë³´ë¥¼ í�¬í•¨í•˜ê³ 있습니다:
Key | Description | Note
--- | --- | ---
`fieldname` | í�¼ì—� ì •ì�˜ë�œ 필드 명 |
`originalname` | 사용�가 업로드한 파� 명 |
`encoding` | 파�� 엔코딩 타입 |
`mimetype` | 파�� Mime 타입 |
`size` | 파�� 바�트(byte) 사�즈 |
`destination` | 파ì�¼ì�´ ì €ìž¥ë�œ í�´ë�” | `DiskStorage`
`filename` | `destination` ì—� ì €ìž¥ë�œ 파ì�¼ 명 | `DiskStorage`
`path` | 업로드ë�œ 파ì�¼ì�˜ ì „ì²´ 경로 | `DiskStorage`
`buffer` | ì „ì²´ 파ì�¼ì�˜ `Buffer` | `MemoryStorage`
### `multer(opts)`
Multer는 옵션 ê°�체를 허용합니다. ê·¸ 중 가장 기본 옵션ì�¸ `dest` 요소는 Multerì—�게 파ì�¼ì�„ 어디로 업로드 í• ì§€ë¥¼ ì•Œë ¤ì¤�니다. ë§Œì�¼ 옵션 ê°�체를 ìƒ�략했다면, 파ì�¼ì�€ 디스í�¬ê°€ 아니ë�¼ 메모리ì—� ì €ìž¥ë� 것 입니다.
기본ì �으로 Multer는 ì�´ë¦„ì�´ 중복ë�˜ëŠ” 것ì�„ 방지하기 위해서 파ì�¼ì�˜ ì�´ë¦„ì�„ 재작성 합니다. í•„ìš”ì—� ë”°ë�¼ 해당 함수는 커스터마ì�´ì§•ì�´ 가능합니다.
Multer로 ì „ë‹¬ 가능한 옵션들ì�€ 다ì�Œê³¼ 같습니다.
Key | Description
--- | ---
`dest` or `storage` | 파ì�¼ì�´ ì €ìž¥ë� 위치
`fileFilter` | ì–´ë–¤ 파ì�¼ì�„ í—ˆìš©í• ì§€ ì œì–´í•˜ëŠ” 함수
`limits` | 업로드 � ��터� 한�
`preservePath` | 파ì�¼ì�˜ base name ëŒ€ì‹ ë³´ì¡´í• íŒŒì�¼ì�˜ ì „ì²´ 경로
`defParamCharset` | 확장 매개변수가 아닌 부분 í—¤ë�” 매개변수 ê°’(예: 파ì�¼ëª…)ì—� ì‚¬ìš©í• ê¸°ë³¸ 문ìž� ì§‘í•©(명시ì � 문ìž� ì§‘í•©ì�„ í�¬í•¨í•˜ì§€ 않ì�Œ). 기본값: `'latin1'`
보통ì�˜ 웹 앱ì—�서는 `dest` 옵션 ì •ë�„ë§Œ í•„ìš”í• ì§€ë�„ 모릅니다. ì„¤ì • 방법ì�€ 아래ì�˜ ì˜ˆì œì—� 나와있습니다.
```javascript
const upload = multer({ dest: 'uploads/' })
```
ë§Œì�¼ 업로드를 ë�” ì œì–´í•˜ê³ ì‹¶ë‹¤ë©´, `dest` 옵션 ëŒ€ì‹ `storage` 옵션ì�„ ì‚¬ìš©í• ìˆ˜ 있습니다. Multer는 ìŠ¤í† ë¦¬ì§€ 엔진ì�¸ `DiskStorage` 와 `MemoryStorage` 를 íƒ‘ìž¬í•˜ê³ ìžˆìŠµë‹ˆë‹¤. ì�¨ë“œíŒŒí‹°ë¡œë¶€í„° ë�” ë§Žì�€ 엔진들ì�„ ì‚¬ìš©í• ìˆ˜ 있습니다.
#### `.single(fieldname)`
`fieldname` ì�¸ìž�ì—� 명시ë�œ ì�´ë¦„ì�˜ 단수 파ì�¼ì�„ ì „ë‹¬ 받습니다. ì�´ 파ì�¼ì�€ `req.file` ì—� ì €ìž¥ë� 것 입니다.
#### `.array(fieldname[, maxCount])`
`fieldname` ì�¸ìž�ì—� 명시ë�œ ì�´ë¦„ì�˜ 파ì�¼ ì „ë¶€ë¥¼ ë°°ì—´ 형태로 ì „ë‹¬ 받습니다. ì„ íƒ�ì �으로 `maxCount` ì—� 명시ë�œ ê°’ ì�´ìƒ�ì�˜ 파ì�¼ì�´ 업로드 ë� 경우 ì—�러를 ì¶œë ¥í• ìˆ˜ 있습니다. ì „ë‹¬ ë�œ ë°°ì—´ 형태ì�˜ 파ì�¼ì�€ `req.files` ì—� ì €ìž¥ë� 것입니다.
#### `.fields(fields)`
`fields` ì�¸ìž�ì—� 명시ë�œ 여러 파ì�¼ì�„ ì „ë‹¬ 받습니다. 파ì�¼ ê°�체는 ë°°ì—´ 형태로 `req.files` ì—� ì €ìž¥ë� 것입니다.
`fields` 는 `name` ê³¼ `maxCount` (ì„ íƒ�사í•) ì�„ í�¬í•¨í•˜ëŠ” ê°�ì²´ì�˜ ë°°ì—´ì�´ì–´ì•¼ 합니다.
ì˜ˆì œ:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
오ì§� í…�스트 필드만 허용합니다. ë§Œì�¼ 파ì�¼ì�´ 업로드 ë�˜ì—ˆì�„ 경우, "LIMIT\_UNEXPECTED\_FILE" 와 ê°™ì�€ ì—�러 코드가 ë°œìƒ�í• ê²ƒìž…ë‹ˆë‹¤. ì�´ëŠ” `upload.fields([])` 와 ê°™ì�€ ë�™ìž‘ì�„ 합니다.
#### `.any()`
ì „ë‹¬ë�œ ëª¨ë“ íŒŒì�¼ì�„ 허용합니다. 파ì�¼ ë°°ì—´ì�€ `req.files` ì—� ì €ìž¥ë� 것입니다.
**주ì�˜:** í•ìƒ� 사용ìž�ê°€ 업로드한 파ì�¼ì�„ 다룬다는 ì �ì�„ 명심하세요. ì•…ì�˜ì �ì�¸ 사용ìž�ê°€ 여러분ì�´ 예측하지 못한 곳으로 파ì�¼ì�„ 업로드 í• ìˆ˜ 있으므로 ì ˆëŒ€ multer를 글로벌 미들웨어로 사용하지 마세요.
### `storage`
#### `DiskStorage`
디스í�¬ ìŠ¤í† ë¦¬ì§€ 엔진ì�€ 파ì�¼ì�„ 디스í�¬ì—� ì €ìž¥í•˜ê¸° 위한 ëª¨ë“ ì œì–´ 기능ì�„ ì œê³µí•©ë‹ˆë‹¤.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
`destination` ê³¼ `filename` ì�˜ ë‘�가지 옵션ì�´ 가능합니다. ë‘� 옵션 모ë‘� 파ì�¼ì�„ ì–´ë””ì—� ì €ìž¥í• ì§€ë¥¼ ì •í•˜ëŠ” 함수입니다.
`destination` 옵션ì�€ ì–´ëŠ� í�´ë�”안ì—� 업로드 한 파ì�¼ì�„ ì €ìž¥í• ì§€ë¥¼ ê²°ì •í•©ë‹ˆë‹¤. ì�´ëŠ” `string` 형태로 주어질 수 있습니다 (예. `'/tmp/uploads'`). ë§Œì�¼ `destination` 옵션ì�´ 주어지지 않으면, ìš´ì˜�ì²´ì œ 시스템ì—�서 임시 파ì�¼ì�„ ì €ìž¥í•˜ëŠ” 기본 ë””ë ‰í† ë¦¬ë¥¼ 사용합니다.
**주:** `destination` ì�„ 함수로 ì‚¬ìš©í• ê²½ìš°, ë””ë ‰í† ë¦¬ë¥¼ ìƒ�성해야 í• ì±…ìž„ì�´ 있습니다. 문ìž�ì—´ì�´ ì „ë‹¬ë� 때, multer는 해당 ë””ë ‰í† ë¦¬ê°€ ìƒ�성ë�˜ì—ˆëŠ”ì§€ 확ì�¸í•©ë‹ˆë‹¤.
`filename` ì�€ í�´ë�”안ì—� ì €ìž¥ë�˜ëŠ” 파ì�¼ 명ì�„ ê²°ì •í•˜ëŠ”ë�° 사용ë�©ë‹ˆë‹¤.
ë§Œì�¼ `filename` ì�´ 주어지지 않는다면, ê°�ê°�ì�˜ 파ì�¼ì�€ 파ì�¼ 확장ìž�를 ì œì™¸í•œ ëžœë�¤í•œ ì�´ë¦„으로 지어질 것입니다.
**주:** Multer는 ì–´ë– í•œ 파ì�¼ 확장ìž�ë�„ 추가하지 않습니다. 사용ìž� 함수는 파ì�¼ 확장ìž�를 ì˜¨ì „ížˆ í�¬í•¨í•œ 파ì�¼ëª…ì�„ 반환해야 합니다.
ê²°ì •ì�„ ë�•기 위해 ê°�ê°�ì�˜ 함수는 ìš”ì² ì •ë³´ (`req`) 와 파ì�¼ (`file`) ì—� 대한 ì •ë³´ë¥¼ 모ë‘� ì „ë‹¬ 받습니다.
`req.body` 는 ì™„ì „ížˆ 채워지지 않았ì�„ 수ë�„ 있습니다. ì�´ëŠ” í�´ë�¼ì�´ì–¸íŠ¸ê°€ 필드와 파ì�¼ì�„ 서버로 ì „ì†¡í•˜ëŠ” 순서ì—� ë”°ë�¼ 다릅니다.
#### `MemoryStorage`
메모리 ìŠ¤í† ë¦¬ì§€ 엔진ì�€ 파ì�¼ì�„ 메모리ì—� `Buffer` ê°�체로 ì €ìž¥í•©ë‹ˆë‹¤. ì�´ì—� 대해서는 ì–´ë–¤ 옵션ë�„ 없습니다.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
메모리 ìŠ¤í† ë¦¬ì§€ 사용시, 파ì�¼ ì •ë³´ëŠ” 파ì�¼ ì „ì²´ë¥¼ í�¬í•¨í•˜ëŠ” `buffer` ë�¼ê³ 불리는 필드를 í�¬í•¨í• 것입니다.
**주ì�˜**: 메모리 ìŠ¤í† ë¦¬ì§€ë¥¼ 사용시, 매우 í�° 사ì�´ì¦ˆì�˜ 파ì�¼ì�„ 업로드 하거나 ë§Žì�€ ì–‘ì�˜ 비êµ�ì � ìž‘ì�€ 파ì�¼ë“¤ì�„ 매우 ë¹ ë¥´ê²Œ 업로드 하는 경우 ì�‘ìš© 프로그램ì�˜ 메모리 부족ì�´ ë°œìƒ� í• ìˆ˜ 있습니다.
### `limits`
다ì�Œì�˜ ì„ íƒ�ì � ì†�성ì�˜ í�¬ê¸° ì œí•œì�„ ì§€ì •í•˜ëŠ” ê°�체입니다. Multer 는 ì�´ ê°�체를 busboy로 ì§�ì ‘ ì „ë‹¬í•©ë‹ˆë‹¤. ì†�성들ì—� 대한 ìž�세한 ë‚´ìš©ì�€ [busboy's page](https://github.com/mscdex/busboy#busboy-methods) ì—�서 확ì�¸ 하실 수 있습니다.
다ì�Œê³¼ ê°™ì�€ ì •ìˆ˜ 값들ì�´ 가능합니다:
�성 | 설명 | 기본값
--- | --- | ---
`fieldNameSize` | 필드명 사�즈 최대값 | 100 bytes
`fieldSize` | 필드값 사�즈 최대값 | 1MB
`fields` | 파ì�¼í˜•ì‹�ì�´ 아닌 필드ì�˜ 최대 개수 | ë¬´ì œí•œ
`fileSize` | multipart 형ì‹� í�¼ì—�서 최대 파ì�¼ 사ì�´ì¦ˆ(bytes) | ë¬´ì œí•œ
`files` | multipart 형ì‹� í�¼ì—�서 파ì�¼ 필드ì�˜ 최대 개수 | ë¬´ì œí•œ
`parts` | For multipart forms, the max number of parts (fields + files) | ë¬´ì œí•œ
`headerPairs` | multipart 형ì‹� í�¼ì—�서 íŒŒì‹±í• í—¤ë�”ì�˜ key=>value ìŒ�ì�˜ 최대 개수| 2000
사ì�´ì¦ˆ ì œí•œì�„ ì§€ì •í•˜ë©´ 서비스 ê±°ë¶€ (DoS) 공격으로부터 사ì�´íŠ¸ë¥¼ 보호하는ë�° ë�„움ì�´ ë�©ë‹ˆë‹¤.
### `fileFilter`
ì–´ëŠ� 파ì�¼ì�„ 업로드 í• ì§€, 혹ì�€ 건너뛸지 ì œì–´í• ìˆ˜ 있게 함수ì—� ì„¤ì •í•©ë‹ˆë‹¤. 해당 함수는 아래와 ê°™ì�„ 것입니다 :
```javascript
function fileFilter (req, file, cb) {
// ì�´ 함수는 boolean ê°’ê³¼ 함께 `cb`를 호출함으로ì�¨ 해당 파ì�¼ì�„ 업로드 í• ì§€ 여부를 나타낼 수 있습니다.
// ì�´ 파ì�¼ì�„ ê±°ë¶€í•˜ë ¤ë©´ 다ì�Œê³¼ ê°™ì�´ `false` 를 ì „ë‹¬í•©ë‹ˆë‹¤:
cb(null, false)
// ì�´ 파ì�¼ì�„ í—ˆìš©í•˜ë ¤ë©´ 다ì�Œê³¼ ê°™ì�´ `true` 를 ì „ë‹¬í•©ë‹ˆë‹¤:
cb(null, true)
// 무언가 ë¬¸ì œê°€ ìƒ�겼다면 ì–¸ì œë‚˜ ì—�러를 ì „ë‹¬í• ìˆ˜ 있습니다:
cb(new Error('I don\'t have a clue!'))
}
```
## �러 핸들�
ì—�러가 ë°œìƒ�í• ë•Œ, multer는 ì—�러를 expressì—� ìœ„ìž„í• ê²ƒìž…ë‹ˆë‹¤. 여러분ì�€ [the standard express way](http://expressjs.com/guide/error-handling.html) 를 ì�´ìš©í•´ì„œ ë©‹ì§„ 오류 페ì�´ì§€ë¥¼ 보여줄 수 있습니다.
ë§Œì�¼ multer 로부터 특별히 ì—�러를 ìº�ì¹˜í•˜ê³ ì‹¶ë‹¤ë©´, ì§�ì ‘ 미들웨어 함수를 호출하세요.
```javascript
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err) {
// ì—…ë¡œë“œí• ë•Œ 오류가 ë°œìƒ�함
return
}
// ì •ìƒ�ì �으로 완료ë�¨
})
})
```
## 커스텀 ìŠ¤í† ë¦¬ì§€ 엔진
ìž�ì‹ ë§Œì�˜ ê³ ìœ í•œ ìŠ¤í† ë¦¬ì§€ 엔진ì�„ 구축하기 위한 ì •ë³´ë¥¼ 얻기 위해서는 [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md) 문서를 ì°¸ê³ í•˜ì„¸ìš”.
## ��센스
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-pt-br.md 0000664 0000000 0000000 00000033152 15213763722 0020541 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer é um middleware node.js para manipulação `multipart/form-data`, que é usado principalmente para fazer upload de arquivos. Foi escrito em cima do [busboy](https://github.com/mscdex/busboy) para máxima eficiência.
**NOTA**: Multer não processará nenhum formulário que não seja multipart (`multipart/form-data`).
## Traduções
Este README também está disponÃvel em outros idiomas:
- [English](https://github.com/expressjs/multer/blob/main/README.md) (Inglês)
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (�rabe)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (Espanhol)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (Chinês)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (Coreano)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (Russo)
- [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) (Vietnã)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (Português Brasil)
- [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) (Francês)
- [O'zbek tili](https://github.com/expressjs/multer/blob/main/doc/README-uz.md) (Uzbequistão)
## Instalação
```sh
$ npm install --save multer
```
## Uso
Multer adiciona um objeto `body` e um `file` ou objeto `files` para objeto `request`. O objeto `body` contém os valores dos campos de texto do formulário, o objeto `file` ou `files` contém os arquivos enviados por meio do formulário.
Exemplo de uso básico:
Não esqueça o `enctype="multipart/form-data"` em seu formulário.
```html
```
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file é um arquivo `avatar`
// req.body conterá os campos de texto, se houver
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files é um array de arquivos `photos`
// req.body conterá os campos de texto, se houver
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files é um objeto (String -> Array) onde fieldname é a chave e o valor é array de arquivos
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body conterá os campos de texto, se houver
})
```
Caso você precise lidar com formulário text-only multipart, você deve usar o método `.none()`:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body contém os campos de texto
})
```
Aqui está um exemplo de como o multer é usado em um formulário HTML. Onde adicionamos `enctype="multipart/form-data"` no form e no input `name="uploaded_file"`:
```html
```
Então, em seu arquivo javascript, você adicionaria essas linhas para acessar o arquivo e o corpo. É importante que você use o valor do campo `name` do formulário em sua função de upload. Isso informa ao multer em qual campo da solicitação ele deve procurar os arquivos. Se esses campos não forem iguais no formulário HTML e no seu servidor, seu upload falhará:
```javascript
const multer = require('multer')
const upload = multer({ dest: './public/data/uploads/' })
app.post('/stats', upload.single('uploaded_file'), function (req, res) {
// req.fileé o nome do seu arquivo no formato acima, aqui 'uploaded_file'
// req.body irá conter os campos de texto, se houver algum
console.log(req.file, req.body)
});
```
## API
### Informação de arquivo
Cada arquivo contém as seguintes informações:
Key | Descrição | Nota
--- | --- | ---
`fieldname` | Nome do campo especificado no formulário |
`originalname` | Nome do arquivo no computador do usuário |
`encoding` | Tipo de codificação do arquivo |
`mimetype` | Tipo Mime do arquivo |
`size` | Tamanho do arquivo em bytes |
`destination` | A pasta na qual o arquivo foi salvo | `DiskStorage`
`filename` | O nome do arquivo dentro do `destination` | `DiskStorage`
`path` | O caminho completo para o arquivo enviado | `DiskStorage`
`buffer` | O `Buffer` do arquivo inteiro | `MemoryStorage`
### `multer(opts)`
Multer aceita um objeto de opções, a propriedade mais básica é o `dest`, que diz ao Multer onde fazer o upload dos arquivos. No caso de você omitir o objeto de opções, os arquivos serão mantidos na memória e nunca gravados no disco.
Por padrão, Multer irá renomear os arquivos para evitar conflitos de nomes. A função de renomeação pode ser personalizada de acordo com suas necessidades.
A seguir estão as opções que podem ser passadas para o Multer.
Key | Descrição
--- | ---
`dest` ou `storage` | Onde armazenar os arquivos
`fileFilter` | Função para controlar quais arquivos são aceitos
`limits` | Limites dos dados enviados
`preservePath` | Mantenha o caminho completo dos arquivos em vez de apenas o nome base
`defParamCharset` | Conjunto de caracteres padrão para usar em valores de parâmetros de cabeçalho de parte (por exemplo, nome do arquivo) que não são parâmetros estendidos (que contêm um conjunto de caracteres explÃcito). Padrão: `'latin1'`
Em um web app básico, somente o `dest` pode ser necessário, e configurado como mostrado no exemplo a seguir:
```javascript
const upload = multer({ dest: 'uploads/' })
```
Se você quiser mais controle sobre seus envios, você ter que usar a opção `storage` em vez de `dest`. Multer vem com motores de armazenamento `DiskStorage` e `MemoryStorage`; Mais mecanismos estão disponÃveis de terceiros.
#### `.single(fieldname)`
Aceite um único arquivo com o nome `fieldname`. O arquivo único será armazenado em `req.file`.
#### `.array(fieldname[, maxCount])`
Aceite múltiplos arquivos, todos com o nome `fieldname`. Opcional, gera um erro se forem enviados mais de `maxCount`. O array de arquivos serão armazenados em
`req.files`.
#### `.fields(fields)`
Aceita uma mistura de arquivos, especificada por `fields`. Um objeto com um array de arquivos será armazenado em `req.files`.
`fields` deve ser uma matriz de objetos com `name` e opcionalmente com `maxCount`.
Exemplo:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
Aceite apenas campo de texto. Se algum upload de arquivo for feito, um erro com código "LIMIT\_UNEXPECTED\_FILE" será emitido.
#### `.any()`
Aceita todos os arquivos que são enviados. Uma matriz de arquivos será armazenada em
`req.files`.
**AVISO:** Certifique-se de sempre manipular os arquivos que um usuário envia.
Nunca adicione o Multer como global no middleware, já que um usuário mal-intencionado poderia fazer upload de arquivos para uma rota que você não previu. Use esta função apenas nas rotas onde você está lidando com os arquivos enviados.
### `storage`
#### `DiskStorage`
O mecanismo de armazenamento em disco oferece controle total sobre o armazenamento de arquivos em disco.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
Existem duas opções disponÃveis, `destination` e `filename`. Ambas são funções que determinam onde o arquivo deve ser armazenado.
`destination` é usado para determinar em qual pasta os arquivos enviados devem ser armazenados. Isso também pode ser dado como uma `string` (e.g. `'/tmp/uploads'`). Se não é dada `destination`, o diretório padrão do sistema operacional para arquivos temporários é usado.
**Nota:** Você é responsável por criar o diretório ao fornecer o "destino" com uma função. Ao passar uma string, o Multer se certificará de que o diretório foi criado para você.
`filename` é usado para determinar qual arquivo deve ser nomeado dentro da pasta.
Se não for passado `filename`, cada arquivo receberá um nome aleatório que não inclui nenhuma extensão de arquivo.
**Nota:** Multer não adicionará nenhuma extensão de arquivo para você, sua função é retornar um nome para o arquivo completo com a extensão de arquivo.
Cada função é passada pelo request (`req`) e algumas informações sobre o arquivo (`file`) para ajudar com a decisão.
Observe que `req.body` pode não ter sido totalmente preenchido ainda. Isso depende da ordem na qual o cliente transmite campos e arquivos para o servidor.
Para entender a convenção de chamada usada no callback (precisando passar
null como o primeiro parâmetro), consulte em
[Manipulação de erros no Node.js](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors)
#### `MemoryStorage`
O mecanismo de armazenamento na memória, armazena os arquivos na memória como um objeto `Buffer`. Não tendo opções.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
Ao usar o armazenamento de memória, as informações do arquivo conterão um campo chamado `buffer` que contém o arquivo inteiro.
**AVISO**: Fazer upload de arquivos muito grandes ou arquivos relativamente pequenos em grande número muito rapidamente pode fazer com que o aplicativo fique sem memória quando o armazenamento de memória é usado.
### `limits`
Um objeto que especifica os limites de tamanho das seguintes propriedades opcionais. O Multer passa diretamente o objeto para o busboy, e os detalhes das propriedades podem ser encontrados em [busboy's page](https://github.com/mscdex/busboy#busboy-methods).
Os seguintes valores inteiros estão disponÃveis:
Key | Descrição | Padrão
--- | --- | ---
`fieldNameSize` | Tamanho máximo do nome de campo| 100 bytes
`fieldSize` | Tamanho máximo do valor do campo (in bytes) | 1MB
`fields` | Max number of non-file fields | Infinity
`fileSize` | Para formulários multipart, o tamanho máximo do arquivo (in bytes) | Infinity
`files` | Para formulários multipart, o número máximo de campos de arquivos | Infinity
`parts` | Para formulários multipart, o número máximo de parts (fields + files) | Infinity
`headerPairs` | Para formulários multipart, o número máximo do header key=>value, para analisar | 2000
A especificação dos limites pode ajudar a proteger seu site contra ataques de negação de serviço (DoS).
### `fileFilter`
Defina isso para uma função para controlar quais arquivos devem ser enviados e quais devem ser ignorados.
A função deve ficar assim:
```javascript
function fileFilter (req, file, cb) {
// A função deve chamar `cb` com um booleano
// para indicar se o arquivo deve ser aceito
// Para rejeitar este arquivo passe `false`, assim:
cb(null, false)
// Para aceitar o arquivo passe `true`, assim:
cb(null, true)
// Você sempre pode passar um erro se algo der errado:
cb(new Error('I don\'t have a clue!'))
}
```
## Error handling
Quando encontrar um erro, Multer delegará o erro para Express. Você pode exibir uma boa página de erro usando [the standard express way](http://expressjs.com/guide/error-handling.html).
Se você quer pegar erros especificamente do Multer, você pode enviar para o função de middleware. Além disso, se você quiser pegar apenas [os erros do Multer](https://github.com/expressjs/multer/blob/main/lib/multer-error.js), você pode usar a classe `MulterError` que está ligado ao objeto `multer` (e.g. `err instanceof multer.MulterError`).
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Ocorreu um erro durante o upload.
} else if (err) {
// Ocorreu um erro durante o upload.
}
// Tudo correu bem.
})
})
```
## Mecanismo de armazenamento personalizado
Para obter informações sobre como criar seu próprio mecanismo de armazenamento, veja [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## Licença
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-ru.md 0000664 0000000 0000000 00000037715 15213763722 0020154 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer — �то middleware дл� фреймворка express дл� обработки `multipart/form-data`, нужна� в первую очередь при загрузке файлов. �апи�ана как обертка над [busboy](https://github.com/mscdex/busboy) дл� ее мак�имально �ффективного и�пользовани�.
**В�Ж�О**: Multer не обрабатывает никакой другой тип форм, кроме `multipart/form-data`.
## Переводы
Ðто README также доÑ�тупно на других Ñ�зыках:
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (араб�кий)
- [English](https://github.com/expressjs/multer/blob/main/README.md) (�нглий�кий)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (И�пан�кий)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (КитайÑ�кий)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (КорейÑ�кий)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (бр Португаль�кий)
## У�тановка
```sh
$ npm install --save multer
```
## И�пользование
Multer добавл�ет объект `body` и объект `file` (или `files`) внутрь объекта `request`. Объект `body` �одержит значени� тек�товых полей формы, объект `file` (`files`) �одержит файл или файлы, загружаемые через форму.
Про�той пример и�пользовани�:
�е забывайте про `enctype="multipart/form-data"` в вашей форме.
```html
```
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file - файл `avatar`
// req.body �охранит тек�товые пол�, е�ли они будут
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files - ма��ив файлов `photos`
// req.body �охранит тек�товые пол�, е�ли они будут
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files - объект (String -> Array), где fieldname - ключ, и значение - ма��ив файлов
//
// например:
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body �охранит тек�товые пол�, е�ли они будут
})
```
Е�ли вам нужно обработать multipart-форму, �одержащую только тек�т, и�пользуйте метод `.none()`:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body �одержит тек�товые пол�
})
```
## API
### Информаци� о файлах
Каждый файл �одержит �ледующую информацию:
Ключ | Опи�ание | Замечани�
--- | --- | ---
`fieldname` | Им� пол�, заданное в форме |
`originalname` | Им� файла на компьютере пользовател� |
`encoding` | Кодировка файла |
`mimetype` | Mime-тип файла |
`size` | Размер файла в байтах |
`destination` | Каталог, где будет �охранен файл | `DiskStorage`
`filename` | Им� файла без `destination` | `DiskStorage`
`path` | Полный путь к загружаемому файлу | `DiskStorage`
`buffer` | `Buffer` из в�его файла | `MemoryStorage`
### `multer(opts)`
Multer принимает объект � опци�ми. Базова� опци� `dest` указывает Multer, куда загружать файлы. Е�ли вы не указываете объект � опци�ми, файлы будут находить�� в пам�ти и не будут запи�аны на ди�к.
По умолчанию, Multer переименовывает файлы, чтобы избежать конфликтов. Ðто наÑ�траиваемо под ваши потребноÑ�ти.
Следующие опции могут быть переданы Multer.
Ключ | Опи�ание
--- | ---
`dest` или `storage` | Где �охран�ть файлы
`fileFilter` | Функци� дл� контрол� прин�ти� файлов
`limits` | Ограничени� по загрузке
`preservePath` | Сохран�ть полный путь к файлам вме�то только базового имени
`defParamCharset` | Кодировка по умолчанию дл� значений параметров заголовков ча�тей (например, им� файла), которые не �вл�ют�� ра�ширенными параметрами (не �одержат �вную кодировку). По умолчанию: `'latin1'`
Обычно дл� веб-приложени� нужно об�зательно переопределить `dest`, как показано в примере ниже.
```javascript
const upload = multer({ dest: 'uploads/' })
```
Е�ли вам нужно больше возможно�тей дл� управлени� приложением, можно и�пользовать `storage` вме�то `dest`. Multer по�тавл�ет�� � двум� движками работы � пам�тью, `DiskStorage` и `MemoryStorage`, другие движки можно найти у �торонних разработчиков.
#### `.single(fieldname)`
Принимает один файл � именем `fieldname`. Файл будет �охранен в `req.file`.
#### `.array(fieldname[, maxCount])`
Принимает ма��ив файлов � именем `fieldname`. Опционально можно задать ошибку при попытке загрузки более `maxCount` файлов. Ма��ив файлов будет �охранен в `req.files`.
#### `.fields(fields)`
Принимает набор файлов, определенных в `fields`. Объект � ма��ивом файлов будет �охранен в `req.files`.
`fields` должен быть ма��ивом объектов � пол�ми `name` и опциональным `maxCount`.
�апример:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
Принимает только тек�товые пол� формы. При попытке загрузки файла падает � ошибкой "LIMIT\_UNEXPECTED\_FILE".
#### `.any()`
Принимает в�е переданные файлы. Ма��ив файлов будет �охранен в `req.files`.
**ПРЕДУПРЕЖДЕ�ИЕ:** Убедите�ь в корректной обработке загрузки файлов вашим приложением. �икогда не и�пользуйте Multer как middleware глобально, е�ли пользователь может загрузить вредоно�ные файлы, и тем �амым нарушить работу вашего приложени�. И�пользуйте �тот метод, только е�ли вы полно�тью управл�ете проце��ом загрузки файлов.
### `storage`
#### `DiskStorage`
Движок ди�кового про�тран�тва. Дает полный контроль над размещением файлов на ди�к.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
До�тупно две опции, ра�положение `destination` и им� файла `filename`. Обе �ти функции определ�ют, где будет находить�� файл по�ле загрузки.
`destination` и�пользует��, чтобы задать каталог, в котором будут размещены файлы. Может быть задан �трокой (например, `'/tmp/uploads'`). Е�ли не задано ра�положение `destination`, операционна� �и�тема во�пользует�� дл� �охранени� каталогом дл� временных файлов.
**Важно:** Вы должны �оздать каталог, когда и�пользуете `destination`. При передачи в каче�тве аргумента �троки, Multer провер�ет, что каталог �оздан.
`filename` и�пользует��, чтобы определить, как будет назван файл внутри каталога. Е�ли
им� файла `filename` не задано, каждому файлу будет �конфигурировано �лучайное им� без ра�ширени� файла.
**Важно:** Multer не добавл�ет никакого файлового ра�ширени�, ваша функци� должна возвращать им� файла � необходимым ра�ширением.
В аргументах каждой функции прокидывает�� запро� (`req`) и набор информации о файле (`file`).
Обратите внимание, что `req.body` может быть не полноÑ�тью заполнено. Ðто завиÑ�ит от порÑ�дка отправки клиентом полей и файлов на Ñ�ервер.
#### `MemoryStorage`
Движок оперативной пам�ти �охран�ет файлы в пам�ти как объекты типа `Buffer`. В �том �лучае нет никаких дополнительных опций.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
Когда вы и�пользуете �тот тип передачи, информаци� о файле будет �одержать поле `buffer`, которое �одержит ве�ь файл.
**ПРЕДУПРЕЖДЕ�ИЕ**: Загрузка очень больших файлов, или отно�ительно небольших файлов в большом количе�тве может вызвать переполнение пам�ти.
### `limits`
Объект, у�танавливающий ограничени�. Multer прокидывает �тот объект напр�мую в busboy, по�тому детали можно по�мотреть
[на �транице � методами busboy](https://github.com/mscdex/busboy#busboy-methods).
До�тупны �ледующие целочи�ленные значени�:
Ключ | Опи�ание | Значение по умолчанию
--- | --- | ---
`fieldNameSize` | Мак�имальный размер имени файла | 100 bytes
`fieldSize` | Мак�имальный размер значени� пол� | 1MB
`fields` | Мак�имальное количе�тво не-файловых полей | �е ограничено
`fileSize` | Мак�имальный размер файла в байтах дл� multipart-форм | �е ограничен
`files` | Мак�имальное количе�тво полей � файлами дл� multipart-форм | �е ограничено
`parts` | Мак�имальное количе�тво полей � файлами дл� multipart-форм (пол� плю� файлы) | �е ограничено
`headerPairs` | Мак�имальное количе�тво пар ключ-значение key=>value дл� multipart-форм, которое обрабатывает�� | 2000
У�тановка ограничений может помочь защитить ваш �айт от DoS-атак.
### `fileFilter`
Задают функцию дл� того, чтобы решать, какие файлы будут загружены, а какие — нет. Функци� может выгл�деть так:
```javascript
function fileFilter (req, file, cb) {
// Функци� должна вызывать `cb` � булевым значением,
// которое показывает, �ледует ли прин�ть файл
// Чтобы отклонить, прокиньте в аргументы `false` так:
cb(null, false)
// Чтобы прин�ть файл, и�пользует�� как аргумент `true` таким образом:
cb(null, true)
// Вы можете в�егда вернуть ошибку, е�ли что-то пошло не так:
cb(new Error('I don\'t have a clue!'))
}
```
## Обработка ошибок
Когда выбра�ывает�� и�ключение, Multer делегирует его обработку Express. Вы можете выводить �траницу ошибки [�тандартными дл� express �по�обами](http://expressjs.com/guide/error-handling.html).
Е�ли вы хотите отлавливать ошибки конкретно от Multer, вам нужно вызывать �об�твенную middleware дл� их обработки. Еще, е�ли вы хотите отлавливать [и�ключительно ошибки Multer](https://github.com/expressjs/multer/blob/main/lib/make-error.js#L1-L9), вы можете и�пользовать кла�� `MulterError`, который прив�зан к объекту `multer` (например, `err instanceof multer.MulterError`)
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Случила�ь ошибка Multer при загрузке.
} else {
// При загрузке произошла неизве�тна� ошибка.
}
// В�е прекра�но загрузило�ь.
})
})
```
## Соб�твенные движки дл� �охранени� файлов
Чтобы получить информацию, как �оздать �об�твенный движок дл� обработки загрузки файлов, �мотрите �траницу [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## Лицензи�
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-tr.md 0000664 0000000 0000000 00000035133 15213763722 0020143 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer, `multipart/form-data` tipi formları işlemek için kullanılan bir Node.js middleware’idir ve genellikle dosya yükleme işlemlerinde kullanılır.
Maksimum verimlilik için [busboy](https://github.com/mscdex/busboy) üzerine yazılmıştır.
**NOT:** Multer, `multipart/form-data` olmayan formları işlemeyecektir.
## Çeviriler
Bu README dosyası ayrıca diğer dillerde de mevcuttur:
| | |
| ------------------------------------------------------------------------------ | --------------- |
| [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) | Arapça |
| [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) | Çince |
| [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) | Fransızca |
| [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) | Korece |
| [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) | Brezilya Portekizcesi |
| [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) | Rusça |
| [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) | İspanyolca |
| [O'zbek tili](https://github.com/expressjs/multer/blob/main/doc/README-uz.md) | Özbekçe |
| [Việt Nam](https://github.com/expressjs/multer/blob/main/doc/README-vi.md) | Vietnamca |
| [Türkçe](https://github.com/expressjs/multer/blob/main/doc/README-tr.md) | Türkçe |
## Kurulum
```sh
$ npm install multer
```
## Kullanım
Multer, `request` nesnesine bir `body` nesnesi ve bir `file` veya `files` nesnesi ekler. `body` nesnesi formdaki metin alanlarının değerlerini içerir; `file` veya `files` nesnesi ise form aracılığıyla yüklenen dosyaları içerir.
Temel kullanım örneği:
Formunuzda enctype="multipart/form-data" eklemeyi unutmayın.
```html
```
```javascript
const express = require("express");
const multer = require("multer");
const upload = multer({ dest: "uploads/" });
const app = express();
app.post("/profile", upload.single("avatar"), function (req, res, next) {
// req.file `avatar` dosyasıdır
// req.body varsa formdaki metin alanlarını tutar
});
app.post(
"/photos/upload",
upload.array("photos", 12),
function (req, res, next) {
// req.files `photos` dosyalarının dizisidir
// req.body varsa metin alanlarını içerir
}
);
const uploadMiddleware = upload.fields([
{ name: "avatar", maxCount: 1 },
{ name: "gallery", maxCount: 8 },
]);
app.post("/cool-profile", uploadMiddleware, function (req, res, next) {
// req.files bir nesnedir (String -> Array) ve burada fieldname (alan adı) anahtar, değer ise dosyaların bulunduğu bir dizidir.
// Örneğin:
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body varsa metin alanların içerir
});
```
Sadece metin verilerini içeren bir multipart formu işlemek için .none() metodunu kullanabilirsiniz:
```javascript
const express = require("express");
const app = express();
const multer = require("multer");
const upload = multer();
app.post("/profile", upload.none(), function (req, res, next) {
// req.body metin alanlarını içerir
});
```
İşte multer'ın HTML formunda nasıl kullanıldığına dair bir örnek. `Enctype="multipart/form-data"` ve `name="uploaded_file"` alanlarına özellikle dikkat edin:
```html
```
Ardından JavaScript dosyanızda, hem dosyaya hem de body’ye erişmek için bu satırları eklemeniz gerekir. Upload fonksiyonunuzda formdaki `name` alanı değerini kullanmanız önemlidir. Bu, multer’a request içindeki hangi alanda dosya araması gerektiğini söyler. Eğer bu alanlar HTML formunda ve sunucuda aynı değilse, yükleme başarısız olur.
```javascript
const multer = require("multer");
const upload = multer({ dest: "./public/data/uploads/" });
app.post("/stats", upload.single("uploaded_file"), function (req, res) {
// req.file formdaki dosya, burada 'uploaded_file'
// req.body metin alanlarını içerir
console.log(req.file, req.body);
});
```
## API
### Dosya bilgisi
Her dosya aşağıdaki bilgileri içerir:
| Anahtar | Açıklama | Not |
| -------------- | -------------------------------------- | --------------- |
| `fieldname` | Formdaki alan adı | |
| `originalname` | Kullanıcının bilgisayarındaki dosya adı | |
| `encoding` | Dosyanın kodlama tipi | |
| `mimetype` | Dosyanın MIME tipi | |
| `size` | Dosyanın boyutu (byte) | |
| `destination` | Dosyanın 'destination' içindeki adı | `DiskStorage` |
| `filename` | Dosyanın klasör içindeki adı | `DiskStorage` |
| `path` | Yüklenen dosyanın tam yolu | `DiskStorage` |
| `buffer` | Dosyanın tamamını içeren `Buffer` | `MemoryStorage` |
### `multer(opts)`
Multer bir options (ayarlar) nesnesi kabul eder. En temel seçenek `dest` olup, dosyaların nereye yükleneceğini belirtir. Eğer options nesnesi verilmezse dosyalar bellekte tutulur ve diske yazılmaz.
Varsayılan olarak, ad çakışmalarını önlemek için Multer dosyaları yeniden adlandırır. Yeniden adlandırma fonksiyonu ihtiyacınıza göre özelleştirilebilir.
Multer’a geçirilebilecek seçenekler:
| Anahtar | Açıklama |
| ----------------- | ------------------------------------------------------ |
| `dest` veya `storage` | Dosyaların nereye kaydedileceği |
| `fileFilter` | Hangi dosyaların kabul edileceğini kontrol eden fonksiyon |
| `limits` | Yüklenen veri sınırları |
| `preservePath` | Sadece dosya adı yerine tam yolu saklar |
Ortalama bir web uygulamasında genellikle sadece `dest` gerekir:
```javascript
const upload = multer({ dest: "uploads/" });
```
Daha fazla kontrol için `storage` seçeneğini kullanabilirsiniz. `Multer`, `DiskStorage` ve `MemoryStorage` depolama motorları ile gelir; üçüncü taraf motorlar da mevcuttur.
#### `.single(fieldname)`
Tek bir dosya kabul eder ve `fieldname` ile eşleşen dosyayı `req.file` içine koyar.
#### `.array(fieldname[, maxCount])`
Birden fazla dosya kabul eder ve `fieldname` ile eşleşenleri `req.files` dizisine koyar. Opsiyonel olarak `maxCount`'tan fazla dosya yüklenirse hata verir.
#### `.fields(fields)`
Belirtilen alanlardan dosya kabul eder. fields bir nesne dizisi olup `req.files` içine koyulur.
`fields`, `name` ve isteğe bağlı olarak `maxCount` içeren nesnelerden oluşan bir dizi olmalıdır.
Örnek:
```javascript
[
{ name: "avatar", maxCount: 1 },
{ name: "gallery", maxCount: 8 },
];
```
#### `.none()`
Yalnızca metin alanlarını kabul eder. Herhangi bir dosya yüklenirse,
“LIMIT_UNEXPECTED_FILE� kodlu bir hata verir
#### `.any()`
Ağ üzerinden gelen tüm dosyaları kabul eder. Bir dizi dosya
`req.files` içinde saklanacaktır.
**UYARI:** Kullanıcıların yüklediği dosyaları her zaman kendiniz işlediğinizden emin olun.
Kötü niyetli bir kullanıcı, sizin öngörmediğiniz bir rotaya dosya yükleyebileceğinden, multer'ı asla global bir orta katman yazılımı olarak eklemeyin.
Bu işlevi yalnızca, yüklenen dosyaları işlediğiniz rotalarda kullanın.
### `storage`
#### `DiskStorage`
Disk depolama motoru, dosyaları diske kaydetme konusunda size tam kontrol sağlar.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "/tmp/my-uploads");
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
cb(null, file.fieldname + "-" + uniqueSuffix);
},
});
const upload = multer({ storage: storage });
```
İki seçenek mevcuttur: `destination` ve `filename`. Her ikisi de
dosyanın nerede saklanacağını belirleyen işlevlerdir.
`destination`, yüklenen dosyaların hangi klasörde
saklanacağını belirlemek için kullanılır. Bu, `string` olarak da verilebilir (ör. `'/tmp/uploads'`). Eğer
`destination` verilmezse, işletim sisteminin geçici dosyalar için varsayılan
dizini kullanılır.
**Not:** `destination` iÅŸlevini kullanarak dizin oluÅŸturmaktan siz
sorumlusunuz. Bir string aktardığınızda, multer dizin sizin için
oluşturulduğundan emin olacaktır.
`filename`, dosyanın klasör içinde nasıl adlandırılacağını belirlemek için kullanılır.
`filename` belirtilmezse, her dosyaya dosya uzantısı içermeyen rastgele bir ad verilir.
**Not:** Multer sizin için herhangi bir dosya uzantısı eklemez, işleviniz
dosya uzantısı ile birlikte tam bir dosya adı döndürmelidir.
Her fonksiyona, karar vermeyi kolaylaştırmak için hem istek (`req`) hem de dosya
hakkında bazı bilgiler (`file`) aktarılır.
`req.body`'nin henüz tam olarak doldurulmamış olabileceğini unutmayın. Bu,
istemcinin alanları ve dosyaları sunucuya aktarma sırasına bağlıdır.
Geri aramada kullanılan çağırma kuralını anlamak için (ilk parametre olarak null geçilmesi gerekir),
[Node.js hata iÅŸleme](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors)
#### `MemoryStorage`
Bellek depolama motoru, dosyaları bellekte `Buffer` nesneleri olarak depolar.
Herhangi bir seçeneği yoktur.
```javascript
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
```
Bellek depolama kullanıldığında, dosya bilgileri tüm dosyayı içeren
`buffer` adlı bir alan içerir.
**UYARI**: Çok büyük dosyaları veya nispeten küçük dosyaları çok hızlı bir şekilde
çok sayıda yüklemek, bellek depolama kullanıldığında uygulamanızın bellek yetersizliği
sorununa neden olabilir.
### `limits`
Aşağıdaki isteğe bağlı özelliklerin boyut sınırlarını belirten bir nesne. Multer bu nesneyi doğrudan busboy'a aktarır ve özelliklerin ayrıntıları [busboy'un sayfasında](https://github.com/mscdex/busboy#busboy-methods) bulunabilir.
Kullanılabilir tamsayı değerleri şöyledir:
| Anahtar | Açıklama | Varsayılan |
| ---------------- | ------------------------------------------------------------------------ | ------------ |
| `fieldNameSize` | Maksimum alan adı boyutu | 100 bayt |
| `fieldSize` | Maksimum alan deÄŸeri boyutu (byte cinsinden) | 1MB |
| `fields` | Dosya olmayan alanların maksimum sayısı | Sonsuz |
| `fileSize` | Çok parçalı (multipart) formlar için maksimum dosya boyutu (bayt cinsinden) | Sonsuz |
| `files` | Çok parçalı (multipart) formlar için maksimum dosya alanı sayısı | Sonsuz |
| `parts` | Çok parçalı (multipart) formlar için toplam parça sayısı (alan + dosya) | Sonsuz |
| `headerPairs` | Çok parçalı (multipart) formlar için ayrıştırılacak maksimum header anahtar-değer çifti sayısı | 2000 |
Sınırları belirlemek, sitenizi hizmet reddi (DoS) saldırılarına karşı korumaya yardımcı olabilir.
### `fileFilter`
Yüklenecek ve atlanacak dosyaları kontrol etmek için bunu bir işleve ayarlayın.
İşlev şu şekilde olmalıdır:
```javascript
function fileFilter(req, file, cb) {
// Fonksiyon, dosyanın kabul edilip edilmeyeceğini belirtmek için
// boolean bir değerle `cb` fonksiyonunu çağırmalıdır.
// Bu dosyayı reddetmek için false döndürün:
cb(null, false);
// Dosyayı kabul etmek için true döndürün:
cb(null, true);
// Bir hata oluşursa her zaman bir hata da döndürebilirsiniz:
cb(new Error("Ne olduÄŸunu bilmiyorum!"));
}
```
## Hata Yönetimi
Bir hatayla karşılaşıldığında, Multer hatayı Express'e devreder.
[Standart Express yöntemi](http://expressjs.com/guide/error-handling.html) kullanarak güzel bir hata sayfası görüntüleyebilirsiniz.
Özellikle Multer'dan gelen hataları yakalamak istiyorsanız,
orta katman işlevini kendiniz çağırabilirsiniz. Ayrıca, yalnızca [Multer hatalarını](https://github.com/expressjs/multer/blob/main/lib/multer-error.js) yakalamak istiyorsanız, `multer` nesnesine eklenmiş olan `MulterError` sınıfını kullanabilirsiniz (ör. `err instanceof multer.MulterError`).
```javascript
const multer = require("multer");
const upload = multer().single("avatar");
app.post("/profile", function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Yükleme sırasında bir Multer hatası oluştu
} else if (err) {
// Yükleme sırasında bilinmeyen bir hata oluştu
}
// Her şey sorunsuz geçti.
});
});
```
## Özel depolama motoru
Kendi depolama motorunuzu nasıl oluşturacağınız hakkında bilgi için [Multer Depolama Motoru](https://github.com/expressjs/multer/blob/main/StorageEngine.md) bölümüne bakın.
## Lisans
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-uz.md 0000664 0000000 0000000 00000031371 15213763722 0020154 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer - bu nodejs middleware bo'lib, asosan `multipart/form-data` shaklda yuborilgan fayllarni yuklashda ishlatiladi. Yuqori samaradorlikka erishish uchun [busboy](https://github.com/mscdex/busboy)ning ustiga yozilgan.
**Muhim**: Multer `multipart` bo'lmagan har qanday formani qayta ishlamaydi.
## Tarjimalar
Bu README boshqa tillarda ham mavjud:
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (arabcha)
- [English](https://github.com/expressjs/multer/blob/main/README.md) (inglizcha)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (ispancha)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (xitoycha)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (korescha)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (portugalcha)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (ruscha)
- [Français](https://github.com/expressjs/multer/blob/main/doc/README-fr.md) (fransuzcha)
## O'rnatish
```sh
$ npm install --save multer
```
## Foydalanish
Multer - `request` ob'ektiga `body` va `file` yoki `files` ob'ektini qo'shadi. `body` ob'ekti formaning matn maydonlarining (fields) qiymatlarini o'z ichiga oladi, `file` yoki `files` ob'ekti forma orqali yuklangan fayllarni o'z ichiga oladi.
Sodda ishlatish uchun namuna:
Formada `enctype="multipart/form-data"` qo'shish esdan chiqmasin
```html
```
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file - fayl `avatar`
// req.body agar matnli maydonlar (fields) bo'lsa, ularni saqlanadi
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files - fayllar massivi `photos`
// req.body agar matnli maydonlar (fields) bo'lsa, ularni saqlanadi
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files - bu ob'ekt (String -> Array), matn maydoni(fieldname) - bu key, va qiymat - fayllar massivi
//
// misol:
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body agar matnli maydonlar (fields) bo'lsa, ularni saqlanadi
})
```
Agarda siz faqat matndan iborat multipart form bilan ishlashingiz kerak bo'lsa, `.none()` ishlating:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body matnli maydonlar (fields)ni o'zida saqlaydi
})
```
## API
### Fayl haqida ma'lumot
Har bir fayl quyidagi ma'lumotlarni o'zida saqlaydi:
Kalit(key) | Ta'rif | Eslatma
--- |----------------------------------------| ---
`fieldname` | Formada berilgan maxsus nom |
`originalname` | Foydalanuvchi kompyuteridagi fayl nomi |
`encoding` | Faylning kodlash turi |
`mimetype` | Faylning `mime` turi |
`size` | Fayl hajmi - baytda |
`destination` | Fayl saqlangan papka | `DiskStorage`
`filename` | `destination`ni ichidagi fayl nomi | `DiskStorage`
`path` | Yuklangan faylning to'liq yo'li | `DiskStorage`
`buffer` | Butun boshli fayl `Buffer` tipda | `MemoryStorage`
### `multer(opts)`
Multer qo'shimcha ob'ekt qabul qiladi, ulardan eng asosiysi - `dest`,
Multerga fayllarni qayerga yuklash kerakligini aytadigan xususiyat. Agarda siz qo'shimcha(`options`) ob'ektni tashlab ketsangiz, fayllar xotirada saqlanadi va hech qachon diskka yozilmaydi.
Standart holatda - Multer nomlashda kelib chiqishi mumkin bo'lgan muammolarni oldini olish uchun fayllar nomini o'zgartiradi. O'z talablaringizga mos ravishda nomlash funksiyasini sozlay olashingiz mumkin.
Quyidagilar Multerga qo'shimcha qiymat sifati berilishi mumkin:
Kalit(key) | Ta'rif
--- | ---
`dest` yoki `storage` | Faylni qayerda saqlash
`fileFilter` | Qaysi fayllar qabul qilinishini boshqarish funksiyasi
`limits` | Yuklash chegarasi
`preservePath` | Asosiy nom o'rniga fayllarning to'liq yo'lini saqlash
`defParamCharset` | Kengaytirilgan parametrlar bo'lmagan qism sarlavha parametrlari qiymatlari (masalan, fayl nomi) uchun ishlatish uchun standart belgilar to'plami (aniq belgilar to'plamini o'z ichiga olmaydi). Standart: `'latin1'`
O'rtacha veb-ilovada faqat `dest` kerak bo'lishi mumkin va quyidagicha sozlanishi mumkin
```javascript
const upload = multer({ dest: 'uploads/' })
```
Yuklamalaringizni boshqarishda ko'proq nazoratni xohlasangiz, `dest` o'rniga `storage` tanlovini ishlatishingiz kerak. Multer `DiskStorage` va `MemoryStorage` saqlash motorlari(engines) bilan keladi. Boshqa motorlar(engines) uchun uchinchi tomondan(third parties) ko'proq tanlovlar keladi.
#### `.single(fieldname)`
`fieldname` nomi bilan yagona faylni qabul qiladi. Yagona fayl `req.file` da saqlanadi.
#### `.array(fieldname[, maxCount])`
`fieldname` nomi bilan fayllar massivini qabul qiladi. Agar `maxCount` dan ko'p fayl yuklash urinishi bo'lsa, hatolikni aniqlash imkoniyatini berish mumkin. Fayllar massivi `req.files` da saqlanadi.
#### `.fields(fields)`
`fields`da aniqlangan fayllarni qabul qiladi. Fayllar massivini saqlash uchun `req.files` ichidagi massivda saqlanadi.
`fields` ob'ektida `name` va `maxCount` kalitlar(keys)ni o'z ichiga olishi kerak. Misol:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
Faqatgina matnli maydonlar(fields)ni oladi. Agarda biror fayl yuklansa, "LIMIT\_UNEXPECTED\_FILE" xatoligi yuboriladi.
#### `.any()`
Ushbu so'rov barcha fayllarni qabul qiladi, fayllar `req.files` ichida saqlanadi.
**OGOHLANTIRISH:** Foydalanuvchi yuklagan fayllarni doimo boshqarib turishni unutmang. Ularni boshqa yo'l(route)ni kutmagan holda fayllarini yuklash imkonini beradigan global middleware sifatida multerni sozlamang. Faqatgina yuklangan fayllarni boshqarish kerak bo'lgan yo'l(route)larda ushbu funksiyani ishlating.
### `storage`
#### `DiskStorage`
Diskka saqlash motori(engine) sizga fayllarni saqlashda to'liq nazorat qilish imkonini beradi.
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
`destination` va `filename` qo'shimcha tanlovlari mavjud, ular ikkala ham qaysi papkada faylni saqlash kerakligini aniqlab turadigan funksiyalardir.
`destination` yuklangan fayllarni qaysi papkada saqlash kerakligini aniqlab turadi. Bu, `string` sifatida berilishi mumkin (masalan, `'/tmp/uploads'`). Agar `destination` berilmagan bo'lsa, operatsion tizimning vaqtinchalik fayllar uchun ishlatiladigan papkasini ishlatadi.
**Diqqat:** `destination` ni funksiya sifatida berib bo'lganda papka ochilganligiga o'zingiz javobgar bo'lasiz. Agar `string` sifatida bersangiz, multer papkani o'zi uchun yaratishni ta'minlaydi.
`filename` faylni papka ichida qanday nomlanganligini aniqlaydi. Agar `filename` berilmagan bo'lsa, har bir faylga fayl kengaytmasini o'z ichiga olmagan tasodifiy nom beriladi.
**Diqqat:** Multer siz uchun fayl kengaytmasini qo'shmaydi, sizning funksiyangiz kengaytma bilan to'liq nomni qaytarishi kerak.
Har bir funksiya `req` so'rovini va fayl haqida ma'lumotlarni (`file`) olish uchun o'tkaziladi.
Diqqat qiling, `req.body` hali to'liq to'ldirilmagan bo'lishi mumkin. Bu mijozning maydon(field)larni va fayllarni serverga qanday yuborishiga bog'liq bo'ladi.
Callback funktsiyasida ishlatiladigan chaqirish tartibini tushunish uchun (birinchi parametr sifatida null o‘tkazish talab etilishi) ko‘rish uchun quyidagi manzilga murojaat qiling:
[Node.js da xatoliklarni ushlash](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors)
#### `MemoryStorage`
Xotira saqlash motori fayllarni xotirada `Buffer` ob'ektlar sifatida saqlaydi. Uning qo'shimcha qiymatlari yo‘q.
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
Xotirada saqlash paytida, fayl ma'lumotlari `buffer` deb nomlanadigan maydonni o‘z ichiga oladi.
**DIQQAT:** Juda katta fayllarni yuklash, yoki kichik fayllarni tez-tez yuklash, xotirada saqlash ishlatilganda, sizning ilovangizning xotirasini to'ldirib qo'yishi mumkin.
### `limits`
Quyidagi xususiyatlar o'lchov(limit)larni aniqlaydigan obyekt. Multer ushbu obyektni to'g'ridan-to'g'ri busboy ga o'tkazadi va xususiyatlar tafsilotlari [busboy sahifasida](https://github.com/mscdex/busboy#busboy-methods)dan topishingiz mumkin.
Quyidagi butun qiymatlar mavjud:
Kalit(key) | Ta'rif | Odatiy qiymat
--- |---------------------------------------------------------------------------------------------| ---
`fieldNameSize` | Maksimal maydon nomi o'lchami | 100 bayt
`fieldSize` | Maksimal maydon qiymati o'lchami (baytlarda) | 1MB
`fields` | Fayl bo'lmagan maydonlarning maksimal soni | Cheklanmagan
`fileSize` | Multipart form uchun faylning maksimal o'lchami (baytda) | Cheklanmagan
`files` | Multipart form uchun fayllar sonining maksimal chegarasi | Cheklanmagan
`parts` | Multipart form uchun fayllar sonining maksimal chegarasi (fieldlar va fayllar) | Cheklanmagan
`headerPairs` | Multipart form uchun ma'lumotlar (kalit va qiymat juftliklari) sonining maksimal chegarasi | 2000
Chegaralarni sozlash, DoS-hujumlariga qarshi saytingizni himoya qilishga yordam bera olishi mumkin
### `fileFilter`
Bu, qaysi fayllarni yuklashi, qaysilarini o'tkazib yuborish kerakligini boshqarish uchun funksiya sifatida sozlasa bo'ladi. Funksiya quyidagi ko'rinishda bo'lishi kerak:"
```javascript
function fileFilter (req, file, cb) {
// Bu funksiya, faylni qabul qilish kerakligini anglatish uchun `cb` ni
// boolean qiymat bilan chaqirish kerak.
// Faylni qabul qilishni rad etish uchun false quyudagicha berilishi kerak:
cb(null, false)
// Faylni qabul qiilishni tasdiqlash uchun true quyudagicha berilishi kerak:
cb(null, true)
// Nimadir xato ketsa, siz har doim Error berishingiz mumkin:
cb(new Error('I don\'t have a clue!'))
}
```
## Xatolar bilan ishlash
Xatoga duch kelganda, Multer xatoni Expressga yuboradi. [standart express usuli](http://expressjs.com/guide/error-handling.html)dan foydalanib xatoni tartibliroq chiqarishingiz mumkin.
Agar siz Multerdan chiqqan xatolarni aniqlamoqchi bo'lsangiz o'zingiz `middleware` funksiya yozishingiz mumkin. Shuningdek, agar siz faqat [Multer xatolarini](https://github.com/expressjs/multer/blob/main/lib/multer-error.js) ushlamoqchi bo'lsangiz, siz `multer` ob'ektiga yozilgan `MulterError` class ni ishlatishingiz mumkin (masalan, `err instanceof multer.MulterError`).
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// Yuklanishda Multerdan xatolik yuz berganda.
} else {
// Yuklanishda noma'lum xatolik yuz berganda.
}
// Hammasi muvaffaqqiyatli bo'lganda.
})
})
```
## Maxsus saqlash mexanizmi
O'zingizning saqlash dvigatelingizni qanday yaratish haqida ma'lumot olish: [Maxsus saqlash mexanizmi](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## Litsenziya
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-vi.md 0000664 0000000 0000000 00000032610 15213763722 0020131 0 ustar 00root root 0000000 0000000 # Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer là thư viện trung gian há»— trợ việc xá» lý `multipart/form-data`, mục Ä‘Ãch chÃnh cho việc upload file. Thư viện nà y dá»±a trên [busboy](https://github.com/mscdex/busboy) để hiệu quả hÆ¡n.
**CHÚ �**: Multer sẽ không xỠlý bất kỳ form nà o ngoà i multipart (`multipart/form-data`).
## Dịch:
Các bạn có thể đ�c ở các bản dịch ngôn ngữ khác:
- [English](https://github.com/expressjs/multer/blob/main/README.md) (Tiếng Anh)
- [ç®€ä½“ä¸æ–‡](https://github.com/expressjs/multer/blob/main/doc/README-zh-cn.md) (Chinese)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (Korean)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (Russian)
## Cà i đặt
```sh
$ npm install --save multer
```
## SỠdụng
Multer gắn thêm một object `body` và một object `file` (hoặc `files` trư�ng hợp upload nhi�u file) và o object `request`. Object `body` nà y sẽ chứa các biến text của form, còn object `file` (hoặc `files`) sẽ chứa các file được upload qua form.
Cách sỠsụng:
Phải thêm `enctype="multipart/form-data"` và o form của bạn.
```html
```
```javascript
var express = require('express');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var app = express();
app.post('/profile', upload.single('avatar'), function(req, res, next) {
// req.file là 1 file `avatar` được upload
// req.body sẽ giữ thông tin gắn kèm (vd: text fields), nếu có
});
app.post('/photos/upload', upload.array('photos', 12), function(
req,
res,
next
) {
// req.files là một mảng của các file `photos`
// req.body sẽ giữ thông tin gắn kèm (vd: text fields), nếu có
});
var uploadMiddleware = upload.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 },
]);
app.post('/cool-profile', uploadMiddleware, function(req, res, next) {
// req.files là một object kiểu (String -> Array) mà fieldname là key, và value là mảng các files
//
// vd:
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body sẽ giữ thông tin gắn kèm (vd: text fields), nếu có
});
```
Trong trư�ng hợp bạn cần xỠlý một multipart form chỉ chứa text, bạn nên sỠdụng hà m `.none()`:
```javascript
var express = require('express');
var app = express();
var multer = require('multer');
var upload = multer();
app.post('/profile', upload.none(), function(req, res, next) {
// req.body sẽ giữ thông tin gắn kèm (vd: text fields)
});
```
## API
### Thông tin File được upload
Mỗi file sẽ chứa các thông tin sau:
| Thuá»™c tÃnh | Mô tả | Ghi chú |
| -------------- | --------------------------------------------------------------- | ------------------------- |
| `fieldname` | tên má»—i thuá»™c tÃnh ở trong form |
| `originalname` | Tên của file nằm trên máy của ngư�i dùng, trước khi được upload |
| `encoding` | Kiểu Encoding của file |
| `mimetype` | Mime type cá»§a file | `image/jpeg`, `image/png` |
| `size` | KÃch thước cá»§a file (theo bytes) |
| `destination` | �ư�ng dẫn tới thư mục file được lưu | `DiskStorage` |
| `filename` | Tên của file (ở trong `destination`) | `DiskStorage` |
| `path` | �ư�ng dẫn đầy đủ tới file đã upload | `DiskStorage` |
| `buffer` | Một `Buffer` của toà n bộ file | `MemoryStorage` |
### Tham số `multer(opts)`
Multer chấp nháºn má»™t biến options. CÆ¡ bản là thuá»™c tÃnh `dest`, là nÆ¡i sẽ lưu
file được upload. Trong trư�ng hợp b� qua options nà y, file sẽ được giữ trong
RAM và không được lưu trên ổ cứng.
Mặc định, Multer sẽ đổi tên các file, vì váºy để tránh bị trùng lặp, bạn có thể
tùy biến hà m đổi tên nà y.
Dưới đây là các tùy ch�n mà bạn có thể sỠdụng:
| Thuá»™c tÃnh | Mô tả |
| --------------------- | -------------------------------------------------- |
| `dest` hoặc `storage` | Nơi lưu trữ file |
| `fileFilter` | Hà m để xá» lý chỉ những file nà o má»›i được chấp nháºn |
| `limits` | Giới hạn dung lượng file được upload |
| `preservePath` | Giữ đầy đủ đư�ng dẫn tới file thay vì chỉ tên file |
| `defParamCharset` | Bộ ký tự mặc định để sỠdụng cho các giá trị tham số tiêu đ� phần (và dụ: tên tệp) không phải là tham số mở rộng (không chứa bộ ký tự rõ rà ng). Mặc định: `'latin1'` |
Nói chung với web app, chỉ `dest` mới cần khai báo, như bên dưới:
```javascript
var upload = multer({ dest: 'uploads/' });
```
Nếu bạn muốn tùy biến việc upload, bạn sẽ muốn dùng tùy ch�n `storage` thay vì `dest`.
Multer sẽ sỠdụng 1 trong 2 cách `DiskStorage` và `MemoryStorage`; Hoặc các cách khác (với các thư viện ngoà i).
#### `.single(fieldname)`
Chấp nháºn chỉ má»™t file vá»›i tên thuá»™c tÃnh `fieldname`. File nà y truy cáºp qua `req.file`.
#### `.array(fieldname[, maxCount])`
Chấp nháºn mảng các file, tất cả Ä‘á»�u vá»›i tên `fieldname`. Má»™t lá»—i sẽ bắn ra nếu có
nhi�u hơn `maxCount` file được upload. Các file nà y được lưu ở `req.files`.
#### `.fields(fields)`
Chấp nháºn nhiá»�u file vá»›i thuá»™c tÃnh `fields`. Má»™t object vá»›i mảng các file được lưu ở `req.files`.
`fields` là má»™t mảng các object vá»›i thuá»™c tÃnh `name` và có thể có thuá»™c tÃnh `maxCount` hoặc không.
Và dụ:
```javascript
[{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }];
```
#### `.none()`
Chỉ chấp nháºn các giá trị text trong form. Nếu bất kỳ file được Ä‘Ãnh
kèm, một lỗi với mã "LIMIT_UNEXPECTED_FILE" sẽ bắn ra.
#### `.any()`
Chấp nháºn tất cả file đến từ bất kỳ nguồn nà o. Má»™t mảng các file sẽ được lưu
ở `req.files`.
**CHÚ �:** Hãy chắc chắn bạn không b� qua bất kỳ file nà o mà ngư�i dùng upload.
�ừng bao gi� khai báo Multer như một middleware toà n cục, vì ngư�i dùng có thể upload
các file tới một api nà o đó mà bạn không biết. Chỉ sỠdụng hà m nà y ở trên api mà bạn
muốn xỠlý việc upload file.
### `storage`
#### `DiskStorage`
Cơ chế lưu trữ trên ổ đĩa cho phép bạn có đầy đủ quy�n để thao tác với file.
```javascript
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, '/tmp/my-uploads');
},
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now());
},
});
var upload = multer({ storage: storage });
```
Có 2 tùy ch�n, `destination` và `filename`. Chúng đ�u dùng để xác định nơi nà o
file sẽ được lưu trữ.
`destination` được dùng để xác định thư mục nà o file được upload. Có thể là một
`string` (vd: `'/tmp/uploads'`). Nếu không khai báo `destination`, thư mục tạm
(của hệ đi�u hà nh) sẽ được dùng để chứa các file đó.
**Ghi chú:** Nếu bạn khai báo `destination` là một hà m, bạn phải tự tạo đư�ng
dẫn. Còn nếu truy�n và o một string, multer sẽ đảm bảo việc tạo đư�ng dẫn đó cho bạn.
`filename` được dùng để xác định file nà o sẽ được lưu trong thư mục. Nếu không
có `filename` nà o, má»—i file sẽ nháºn tên ngẫu nhiên mà không bao gồm Ä‘uôi cá»§a file.
**Ghi chú:** Multer sẽ không thêm bất kỳ đuôi file nà o cho bạn, hà m của bạn nên
trả v� một file với đuôi của nó.
Mỗi hà m được truy�n cả ở request (`req`) và thông tin v� file (`file`) để xỠlý.
Chú ý `req.body` có thể không chứa đầy đủ thông tin, phụ thuộc việc thứ tự các
trưá»�ng dữ liệu và file được gá»i tá»›i server lúc nà o.
#### `MemoryStorage`
Memory storage lưu các file ở bộ nhớ máy dưới dạng một object `Buffer`. Nó không
có bất kỳ tùy ch�n nà o.
```javascript
var storage = multer.memoryStorage();
var upload = multer({ storage: storage });
```
Khi sỠdụng memory storage, thông tin file sẽ chứa một trư�ng `buffer`, trư�ng
nà y chứa toà n bộ file.
**CHÚ �**: Việc upload file rất lớn, hoặc tương tự việc nhi�u file nh�, có thể
gây ra trà n bộ nhớ khi memory storage được sỠdụng.
### `limits`
Má»™t object mô tả giá»›i hạn kÃch thước trong thuá»™c tÃnh nên được sá» dụng. Multer truyá»�n object nà y trá»±c tiếp và o busboy, và chi tiết cá»§a busboy có thể xem thêm ở [busboy's page](https://github.com/mscdex/busboy#busboy-methods).
Các số dưới dây cũng có thể được dùng:
| Thuá»™c tÃnh | Mô tả | Giá trị mặc định |
| --------------- | -------------------------------------------------------------------- | ---------------- |
| `fieldNameSize` | �ộ dà i tối đa của tên field | 100 bytes |
| `fieldSize` | KÃch thước tối Ä‘a cá»§a má»—i field (theo bytes) | 1MB |
| `fields` | Số lượng tối đa của các fields không phải là file | Infinity |
| `fileSize` | Cho multipart forms, kÃch thước tối Ä‘a cá»§a file (theo bytes) | Infinity |
| `files` | Cho multipart forms, số lượng file tối đa | Infinity |
| `parts` | Cho multipart forms, số lượng tối đa của parts (gồm fields + files) | Infinity |
| `headerPairs` | Cho multipart forms, số tối đa trong header cặp key=>value để truy�n | 2000 |
Khai báo các giới hạn nà y giúp cho site của bạn chống lại các tấn công nguy hiểm (DoS).
### `fileFilter`
Dùng hà m nà y để xỠlý các file nà o cho phép và bị b� qua. Xem và dụ dưới dây:
```javascript
function fileFilter(req, file, cb) {
// hà m nà y sẽ g�i callback `cb` với 1 biến boolean
// để chỉ ra rằng file có được chấp nháºn hay không
// �ể chặn file nà y, truy�n `false` như sau:
cb(null, false);
// Ä�ể chấp nháºn file nà y, truỳen `true`, như sau:
cb(null, true);
// Hoặc bạn có thể truy�n và o 1 lỗi nếu có vấn đ� xảy ra:
cb(new Error("I don't have a clue!"));
}
```
## Error handling
Khi má»™t lá»—i xảy ra, Multer sẽ gá»i lá»—i đó cho Express. Bạn có thể hiển thị
đẹp hơn sỠdụng [cách bắt lỗi chuẩn của Express](http://expressjs.com/guide/error-handling.html).
Nếu bạn muốn bắt các lá»—i cụ thể từ Multer, bạn có thể tá»± gá»�i hà m trung gian (middleware) nà y. Ngoà i ra, nếu bạn chỉ muốn bắt [lá»—i cá»§a Multer](https://github.com/expressjs/multer/blob/main/lib/multer-error.js), bạn có thể dùng class `MulterError` được Ä‘Ãnh kèm vá»›i chÃnh object `multer` (vd: `err instanceof multer.MulterError`).
```javascript
var multer = require('multer');
var upload = multer().single('avatar');
app.post('/profile', function(req, res) {
upload(req, res, function(err) {
if (err instanceof multer.MulterError) {
// Một lỗi của Multer xảy ra khi upload.
} else if (err) {
// Một lỗi không xác định xảy ra khi upload.
}
// M�i thứ khác chạy ok.
});
});
```
## Tùy ch�n storage engine
�ể là m sao tự xây dựng cơ chế lưu file riêng của mình, hãy xem [Multer Storage Engine](https://github.com/expressjs/multer/blob/main/StorageEngine.md).
## License
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/doc/README-zh-cn.md 0000664 0000000 0000000 00000024646 15213763722 0020544 0 ustar 00root root 0000000 0000000 **æ¤æ–‡æ¡£äºŽ2016å¹´10月3日翻译时multer的版本是1.2.0,它å�¯èƒ½ä¸�是最新的ï¼�**
**甚至å�¯èƒ½å˜åœ¨ç¿»è¯‘错误ï¼�ä½ å�¯èƒ½éœ€è¦�阅读原版英è¯[README](../README.md)**
**æ¤æ–‡æ¡£ä»…ä¾›å�‚考ï¼�**
# Multer [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Test Coverage][test-image]][test-url] [![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
Multer 是一个 node.js ä¸é—´ä»¶ï¼Œç”¨äºŽå¤„ç�† `multipart/form-data` 类型的表å�•æ•°æ�®ï¼Œå®ƒä¸»è¦�ç”¨äºŽä¸Šä¼ æ–‡ä»¶ã€‚å®ƒæ˜¯å†™åœ¨ [busboy](https://github.com/mscdex/busboy) 之上é�žå¸¸é«˜æ•ˆã€‚
**注�**: Multer �会处�任何� `multipart/form-data` 类型的表�数�。
## 其它è¯è¨€
- [العربية](https://github.com/expressjs/multer/blob/main/doc/README-ar.md) (阿拉伯è¯)
- [English](https://github.com/expressjs/multer/blob/main/README.md) (英è¯)
- [Español](https://github.com/expressjs/multer/blob/main/doc/README-es.md) (西ç�牙文)
- [한êµì–´](https://github.com/expressjs/multer/blob/main/doc/README-ko.md) (æœ�鲜è¯)
- [Ру��кий �зык](https://github.com/expressjs/multer/blob/main/doc/README-ru.md) (俄語)
- [Português](https://github.com/expressjs/multer/blob/main/doc/README-pt-br.md) (巴西葡è�„牙è¯)
## 安装
```sh
$ npm install --save multer
```
## 使用
Multer ä¼šæ·»åŠ ä¸€ä¸ª `body` 对象 以å�Š `file` 或 `files` 对象 到 express çš„ `request` 对象ä¸ã€‚
`body` 对象包å�«è¡¨å�•的文本域信æ�¯ï¼Œ`file` 或 `files` 对象包å�«å¯¹è±¡è¡¨å�•ä¸Šä¼ çš„æ–‡ä»¶ä¿¡æ�¯ã€‚
基本使用方法:
```javascript
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file 是 `avatar` 文件的信�
// req.body 将具有文本域数æ�®ï¼Œå¦‚æžœå˜åœ¨çš„è¯�
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files 是 `photos` 文件数组的信�
// req.body 将具有文本域数æ�®ï¼Œå¦‚æžœå˜åœ¨çš„è¯�
})
const uploadMiddleware = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', uploadMiddleware, function (req, res, next) {
// req.files 是一个对象 (String -> Array) 键是文件�,值是文件数组
//
// 例如:
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body 将具有文本域数æ�®ï¼Œå¦‚æžœå˜åœ¨çš„è¯�
})
```
å¦‚æžœä½ éœ€è¦�处ç�†ä¸€ä¸ªå�ªæœ‰æ–‡æœ¬åŸŸçš„表å�•ï¼Œä½ åº”å½“ä½¿ç”¨ `.none()`:
```javascript
const express = require('express')
const app = express()
const multer = require('multer')
const upload = multer()
app.post('/profile', upload.none(), function (req, res, next) {
// req.body 包�文本域
})
```
## API
### 文件信�
�个文件具有下�的信�:
Key | Description | Note
--- | --- | ---
`fieldname` | Field name 由表�指定 |
`originalname` | 用户计算机上的文件的�称 |
`encoding` | 文件编ç � |
`mimetype` | 文件的 MIME 类型 |
`size` | 文件大å°�(å—节å�•ä½�) |
`destination` | ä¿�å˜è·¯å¾„ | `DiskStorage`
`filename` | ä¿�å˜åœ¨ `destination` ä¸çš„æ–‡ä»¶å�� | `DiskStorage`
`path` | å·²ä¸Šä¼ æ–‡ä»¶çš„å®Œæ•´è·¯å¾„ | `DiskStorage`
`buffer` | ä¸€ä¸ªå˜æ”¾äº†æ•´ä¸ªæ–‡ä»¶çš„ `Buffer` | `MemoryStorage`
### `multer(opts)`
Multer 接å�—一个 options å¯¹è±¡ï¼Œå…¶ä¸æœ€åŸºæœ¬çš„æ˜¯ `dest` 属性,这将告诉 Multer å°†ä¸Šä¼ æ–‡ä»¶ä¿�å˜åœ¨å“ªã€‚å¦‚æžœä½ çœ�ç•¥ options 对象,这些文件将ä¿�å˜åœ¨å†…å˜ä¸ï¼Œæ°¸è¿œä¸�会写入ç£�盘。
为了é�¿å…�命å��冲çª�,Multer ä¼šä¿®æ”¹ä¸Šä¼ çš„æ–‡ä»¶å��。这个é‡�命å��功能å�¯ä»¥æ ¹æ�®æ‚¨çš„需è¦�定制。
以下是å�¯ä»¥ä¼ 递给 Multer 的选项。
Key | Description
--- | ---
`dest` or `storage` | 在哪里å˜å‚¨æ–‡ä»¶
`fileFilter` | 文件过滤器,控制哪些文件�以被接�
`limits` | é™�åˆ¶ä¸Šä¼ çš„æ•°æ�®
`preservePath` | ä¿�å˜åŒ…å�«æ–‡ä»¶å��的完整文件路径
`defParamCharset` | ç”¨äºŽéƒ¨åˆ†æ ‡å¤´å�‚数值(例如文件å��)的默认å—符集,这些å�‚æ•°ä¸�是扩展å�‚数(ä¸�包å�«æ˜¾å¼�å—符集)。默认值:`'latin1'`
通常,一般的网页应用,å�ªéœ€è¦�设置 `dest` 属性,åƒ�è¿™æ ·ï¼š
```javascript
const upload = multer({ dest: 'uploads/' })
```
å¦‚æžœä½ æƒ³åœ¨ä¸Šä¼ æ—¶è¿›è¡Œæ›´å¤šçš„æŽ§åˆ¶ï¼Œä½ å�¯ä»¥ä½¿ç”¨ `storage` 选项替代 `dest`。Multer 具有 `DiskStorage` å’Œ `MemoryStorage` 两个å˜å‚¨å¼•擎;å�¦å¤–还å�¯ä»¥ä»Žç¬¬ä¸‰æ–¹èŽ·å¾—æ›´å¤šå�¯ç”¨çš„引擎。
#### `.single(fieldname)`
接å�—一个以 `fieldname` 命å��的文件。这个文件的信æ�¯ä¿�å˜åœ¨ `req.file`。
#### `.array(fieldname[, maxCount])`
接å�—一个以 `fieldname` 命å��的文件数组。å�¯ä»¥é…�ç½® `maxCount` æ�¥é™�åˆ¶ä¸Šä¼ çš„æœ€å¤§æ•°é‡�。这些文件的信æ�¯ä¿�å˜åœ¨ `req.files`。
#### `.fields(fields)`
接å�—指定 `fields` 的混å�ˆæ–‡ä»¶ã€‚这些文件的信æ�¯ä¿�å˜åœ¨ `req.files`。
`fields` 应该是一个对象数组,应该具有 `name` 和�选的 `maxCount` 属性。
Example:
```javascript
[
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]
```
#### `.none()`
å�ªæŽ¥å�—æ–‡æœ¬åŸŸã€‚å¦‚æžœä»»ä½•æ–‡ä»¶ä¸Šä¼ åˆ°è¿™ä¸ªæ¨¡å¼�,将å�‘生 "LIMIT\_UNEXPECTED\_FILE" 错误。这和 `upload.fields([])` çš„æ•ˆæžœä¸€æ ·ã€‚
#### `.any()`
接å�—ä¸€åˆ‡ä¸Šä¼ çš„æ–‡ä»¶ã€‚æ–‡ä»¶æ•°ç»„å°†ä¿�å˜åœ¨ `req.files`。
**è¦å‘Š:** ç¡®ä¿�ä½ æ€»æ˜¯å¤„ç�†äº†ç”¨æˆ·çš„æ–‡ä»¶ä¸Šä¼ 。
永远ä¸�è¦�å°† multer 作为全局ä¸é—´ä»¶ä½¿ç”¨ï¼Œå› 为æ�¶æ„�用户å�¯ä»¥ä¸Šä¼ æ–‡ä»¶åˆ°ä¸€ä¸ªä½ æ²¡æœ‰é¢„æ–™åˆ°çš„è·¯ç”±ï¼Œåº”è¯¥å�ªåœ¨ä½ 需è¦�处ç�†ä¸Šä¼ 文件的路由上使用。
### `storage`
#### ç£�盘å˜å‚¨å¼•擎 (`DiskStorage`)
ç£�盘å˜å‚¨å¼•擎å�¯ä»¥è®©ä½ 控制文件的å˜å‚¨ã€‚
```javascript
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const upload = multer({ storage: storage })
```
有两个选项å�¯ç”¨ï¼Œ`destination` å’Œ `filename`。他们都是用æ�¥ç¡®å®šæ–‡ä»¶å˜å‚¨ä½�置的函数。
`destination` 是用æ�¥ç¡®å®šä¸Šä¼ 的文件应该å˜å‚¨åœ¨å“ªä¸ªæ–‡ä»¶å¤¹ä¸ã€‚也å�¯ä»¥æ��供一个 `string` (例如 `'/tmp/uploads'`)。如果没有设置 `destination`,则使用æ“�作系统默认的临时文件夹。
**注æ„�:** å¦‚æžœä½ æ��供的 `destination` æ˜¯ä¸€ä¸ªå‡½æ•°ï¼Œä½ éœ€è¦�负责创建文件夹。当æ��供一个å—符串,multer 将确ä¿�è¿™ä¸ªæ–‡ä»¶å¤¹æ˜¯ä½ åˆ›å»ºçš„ã€‚
`filename` 用于确定文件夹ä¸çš„æ–‡ä»¶å��的确定。 如果没有设置 `filename`,æ¯�个文件将设置为一个éš�机文件å��,并且是没有扩展å��的。
**注æ„�:** Multer ä¸�ä¼šä¸ºä½ æ·»åŠ ä»»ä½•æ‰©å±•å��ï¼Œä½ çš„ç¨‹åº�应该返回一个完整的文件å��。
æ¯�ä¸ªå‡½æ•°éƒ½ä¼ é€’äº†è¯·æ±‚å¯¹è±¡ (`req`) 和一些关于这个文件的信æ�¯ (`file`)ï¼Œæœ‰åŠ©äºŽä½ çš„å†³å®šã€‚
注æ„� `req.body` å�¯èƒ½è¿˜æ²¡æœ‰å®Œå…¨å¡«å……,这å�–决于å�‘客户端å�‘é€�å—æ®µå’Œæ–‡ä»¶åˆ°æœ�务器的顺åº�。
#### 内å˜å˜å‚¨å¼•擎 (`MemoryStorage`)
内å˜å˜å‚¨å¼•擎将文件å˜å‚¨åœ¨å†…å˜ä¸çš„ `Buffer` 对象,它没有任何选项。
```javascript
const storage = multer.memoryStorage()
const upload = multer({ storage: storage })
```
当使用内å˜å˜å‚¨å¼•擎,文件信æ�¯å°†åŒ…å�«ä¸€ä¸ª `buffer` å—æ®µï¼Œé‡Œé�¢åŒ…å�«äº†æ•´ä¸ªæ–‡ä»¶æ•°æ�®ã€‚
**è¦å‘Š**: å½“ä½ ä½¿ç”¨å†…å˜å˜å‚¨ï¼Œä¸Šä¼ é�žå¸¸å¤§çš„æ–‡ä»¶ï¼Œæˆ–者é�žå¸¸å¤šçš„å°�æ–‡ä»¶ï¼Œä¼šå¯¼è‡´ä½ çš„åº”ç”¨ç¨‹åº�å†…å˜æº¢å‡ºã€‚
### `limits`
一个对象,指定一些数�大�的�制。Multer 通过这个对象使用 busboy,详细的特性�以在 [busboy's page](https://github.com/mscdex/busboy#busboy-methods) 找到。
�以使用下�这些:
Key | Description | Default
--- | --- | ---
`fieldNameSize` | field å��å—æœ€å¤§é•¿åº¦ | 100 bytes
`fieldSize` | field 值的最大长度 | 1MB
`fields` | é�žæ–‡ä»¶ field 的最大数é‡� | æ— é™�
`fileSize` | 在 multipart 表å�•ä¸ï¼Œæ–‡ä»¶æœ€å¤§é•¿åº¦ (å—节å�•ä½�) | æ— é™�
`files` | 在 multipart 表å�•ä¸ï¼Œæ–‡ä»¶æœ€å¤§æ•°é‡� | æ— é™�
`parts` | 在 multipart 表å�•ä¸ï¼Œpart ä¼ è¾“çš„æœ€å¤§æ•°é‡�(fields + files) | æ— é™�
`headerPairs` | 在 multipart 表å�•ä¸ï¼Œé”®å€¼å¯¹æœ€å¤§ç»„æ•° | 2000
设置 limits å�¯ä»¥å¸®åŠ©ä¿�æŠ¤ä½ çš„ç«™ç‚¹æŠµå¾¡æ‹’ç»�æœ�务 (DoS) 攻击。
### `fileFilter`
设置一个函数æ�¥æŽ§åˆ¶ä»€ä¹ˆæ–‡ä»¶å�¯ä»¥ä¸Šä¼ 以å�Šä»€ä¹ˆæ–‡ä»¶åº”该跳过,这个函数应该看起æ�¥åƒ�è¿™æ ·ï¼š
```javascript
function fileFilter (req, file, cb) {
// 这个函数应该调用 `cb` 用boolean值�
// 指示是�应接�该文件
// æ‹’ç»�这个文件,使用`false`,åƒ�è¿™æ ·:
cb(null, false)
// 接å�—这个文件,使用`true`,åƒ�è¿™æ ·:
cb(null, true)
// å¦‚æžœæœ‰é—®é¢˜ï¼Œä½ å�¯ä»¥æ€»æ˜¯è¿™æ ·å�‘é€�一个错误:
cb(new Error('I don\'t have a clue!'))
}
```
## 错误处�机制
当é�‡åˆ°ä¸€ä¸ªé”™è¯¯ï¼Œmulter 将会把错误å�‘é€�ç»™ expressã€‚ä½ å�¯ä»¥ä½¿ç”¨ä¸€ä¸ªæ¯”较好的错误展示页 ([expressæ ‡å‡†æ–¹å¼�](http://expressjs.com/guide/error-handling.html))。
å¦‚æžœä½ æƒ³æ�•æ�‰ multer å�‘å‡ºçš„é”™è¯¯ï¼Œä½ å�¯ä»¥è‡ªå·±è°ƒç”¨ä¸é—´ä»¶ç¨‹åº�ã€‚å¦‚æžœä½ æƒ³æ�•æ�‰ [Multer 错误](https://github.com/expressjs/multer/blob/main/lib/multer-error.js)ï¼Œä½ å�¯ä»¥ä½¿ç”¨ `multer` 对象下的 `MulterError` ç±» (å�³ `err instanceof multer.MulterError`)。
```javascript
const multer = require('multer')
const upload = multer().single('avatar')
app.post('/profile', function (req, res) {
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
// �生错误
} else if (err) {
// �生错误
}
// 一切都好
})
})
```
## 定制å˜å‚¨å¼•擎
å¦‚æžœä½ æƒ³è¦�构建自己的å˜å‚¨å¼•擎,请看 [这里](/StorageEngine.md) 。
## License
[MIT](LICENSE)
[ci-image]: https://github.com/expressjs/multer/actions/workflows/ci.yml/badge.svg
[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml
[test-url]: https://coveralls.io/r/expressjs/multer?branch=main
[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/main
[npm-downloads-image]: https://badgen.net/npm/dm/multer
[npm-url]: https://npmjs.org/package/multer
[npm-version-image]: https://badgen.net/npm/v/multer
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/multer/badge
[ossf-scorecard-visualizer]: https://ossf.github.io/scorecard-visualizer/#/projects/github.com/expressjs/multer
expressjs-multer-2e2af08/index.js 0000664 0000000 0000000 00000005271 15213763722 0017141 0 ustar 00root root 0000000 0000000 var makeMiddleware = require('./lib/make-middleware')
var diskStorage = require('./storage/disk')
var memoryStorage = require('./storage/memory')
var MulterError = require('./lib/multer-error')
function allowAll (req, file, cb) {
cb(null, true)
}
function Multer (options) {
if (options.storage) {
this.storage = options.storage
} else if (options.dest) {
this.storage = diskStorage({ destination: options.dest })
} else {
this.storage = memoryStorage()
}
this.limits = options.limits
this.preservePath = options.preservePath
this.defParamCharset = options.defParamCharset || 'latin1'
this.fileFilter = options.fileFilter || allowAll
}
Multer.prototype._makeMiddleware = function (fields, fileStrategy) {
function setup () {
var fileFilter = this.fileFilter
var filesLeft = Object.create(null)
fields.forEach(function (field) {
if (typeof field.maxCount === 'number') {
filesLeft[field.name] = field.maxCount
} else {
filesLeft[field.name] = Infinity
}
})
function wrappedFileFilter (req, file, cb) {
if ((filesLeft[file.fieldname] || 0) <= 0) {
return cb(new MulterError('LIMIT_UNEXPECTED_FILE', file.fieldname))
}
filesLeft[file.fieldname] -= 1
fileFilter(req, file, cb)
}
return {
limits: this.limits,
preservePath: this.preservePath,
defParamCharset: this.defParamCharset,
storage: this.storage,
fileFilter: wrappedFileFilter,
fileStrategy: fileStrategy
}
}
return makeMiddleware(setup.bind(this))
}
Multer.prototype.single = function (name) {
return this._makeMiddleware([{ name: name, maxCount: 1 }], 'VALUE')
}
Multer.prototype.array = function (name, maxCount) {
return this._makeMiddleware([{ name: name, maxCount: maxCount }], 'ARRAY')
}
Multer.prototype.fields = function (fields) {
return this._makeMiddleware(fields, 'OBJECT')
}
Multer.prototype.none = function () {
return this._makeMiddleware([], 'NONE')
}
Multer.prototype.any = function () {
function setup () {
return {
limits: this.limits,
preservePath: this.preservePath,
defParamCharset: this.defParamCharset,
storage: this.storage,
fileFilter: this.fileFilter,
fileStrategy: 'ARRAY'
}
}
return makeMiddleware(setup.bind(this))
}
function multer (options) {
if (options === undefined) {
return new Multer({})
}
if (typeof options === 'object' && options !== null) {
return new Multer(options)
}
throw new TypeError('Expected object for argument options')
}
module.exports = multer
module.exports.diskStorage = diskStorage
module.exports.memoryStorage = memoryStorage
module.exports.MulterError = MulterError
expressjs-multer-2e2af08/lib/ 0000775 0000000 0000000 00000000000 15213763722 0016235 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/lib/counter.js 0000664 0000000 0000000 00000001072 15213763722 0020252 0 ustar 00root root 0000000 0000000 var EventEmitter = require('events').EventEmitter
function Counter () {
EventEmitter.call(this)
this.value = 0
}
Counter.prototype = Object.create(EventEmitter.prototype)
Counter.prototype.increment = function increment () {
this.value++
}
Counter.prototype.decrement = function decrement () {
if (--this.value === 0) this.emit('zero')
}
Counter.prototype.isZero = function isZero () {
return (this.value === 0)
}
Counter.prototype.onceZero = function onceZero (fn) {
if (this.isZero()) return fn()
this.once('zero', fn)
}
module.exports = Counter
expressjs-multer-2e2af08/lib/file-appender.js 0000664 0000000 0000000 00000003126 15213763722 0021310 0 ustar 00root root 0000000 0000000 function arrayRemove (arr, item) {
var idx = arr.indexOf(item)
if (~idx) arr.splice(idx, 1)
}
function FileAppender (strategy, req) {
this.strategy = strategy
this.req = req
switch (strategy) {
case 'NONE': break
case 'VALUE': break
case 'ARRAY': req.files = []; break
case 'OBJECT': req.files = Object.create(null); break
default: throw new Error('Unknown file strategy: ' + strategy)
}
}
FileAppender.prototype.insertPlaceholder = function (file) {
var placeholder = {
fieldname: file.fieldname
}
switch (this.strategy) {
case 'NONE': break
case 'VALUE': break
case 'ARRAY': this.req.files.push(placeholder); break
case 'OBJECT':
if (this.req.files[file.fieldname]) {
this.req.files[file.fieldname].push(placeholder)
} else {
this.req.files[file.fieldname] = [placeholder]
}
break
}
return placeholder
}
FileAppender.prototype.removePlaceholder = function (placeholder) {
switch (this.strategy) {
case 'NONE': break
case 'VALUE': break
case 'ARRAY': arrayRemove(this.req.files, placeholder); break
case 'OBJECT':
if (this.req.files[placeholder.fieldname].length === 1) {
delete this.req.files[placeholder.fieldname]
} else {
arrayRemove(this.req.files[placeholder.fieldname], placeholder)
}
break
}
}
FileAppender.prototype.replacePlaceholder = function (placeholder, file) {
if (this.strategy === 'VALUE') {
this.req.file = file
return
}
delete placeholder.fieldname
Object.assign(placeholder, file)
}
module.exports = FileAppender
expressjs-multer-2e2af08/lib/make-middleware.js 0000664 0000000 0000000 00000017062 15213763722 0021631 0 ustar 00root root 0000000 0000000 var is = require('type-is')
var Busboy = require('busboy')
var appendField = require('append-field')
var Counter = require('./counter')
var MulterError = require('./multer-error')
var FileAppender = require('./file-appender')
var removeUploadedFiles = require('./remove-uploaded-files')
function drainStream (stream) {
stream.on('readable', () => {
while (stream.read() !== null) {}
})
}
function makeMiddleware (setup) {
return function multerMiddleware (req, res, next) {
if (!is(req, ['multipart'])) return next()
var options = setup()
var limits = options.limits
var storage = options.storage
var fileFilter = options.fileFilter
var fileStrategy = options.fileStrategy
var preservePath = options.preservePath
var defParamCharset = options.defParamCharset
req.body = Object.create(null)
var busboy
var appender = null
var isDone = false
var readFinished = false
var errorOccured = false
var pendingWrites = new Counter()
var uploadedFiles = []
var pendingFiles = []
function done (err) {
var called = false
function onFinished () {
if (called) return
called = true
next(err)
}
if (isDone) return
isDone = true
if (busboy) {
req.unpipe(busboy)
setImmediate(() => {
busboy.removeAllListeners()
})
}
drainStream(req)
req.resume()
// - if responding with an error, drain request body before calling
// next(err) -- avoids EPIPE on the client (server closing connection
// while the client is still sending the request body)
// - also listen for 'close' so we don't hang when the client aborts (stream may never 'end')
// - skip waiting if the stream is already destroyed (e.g. client aborted)
if (err && req.readable && !req.destroyed) {
req.once('end', onFinished)
req.once('error', onFinished)
req.once('close', onFinished)
return
}
next(err)
}
function indicateDone () {
if (readFinished && pendingWrites.isZero() && !errorOccured) done()
}
function abortWithError (uploadError, skipPendingWait) {
if (errorOccured) return
errorOccured = true
function finishAbort () {
function remove (file, cb) {
storage._removeFile(req, file, cb)
}
var filesToRemove = uploadedFiles.concat(
pendingFiles.filter(function (f) { return f.path })
)
pendingFiles = []
removeUploadedFiles(filesToRemove, remove, function (err, storageErrors) {
if (err) return done(err)
uploadError.storageErrors = storageErrors
done(uploadError)
})
}
if (skipPendingWait) {
finishAbort()
} else {
pendingWrites.onceZero(finishAbort)
}
}
function abortWithCode (code, optionalField) {
abortWithError(new MulterError(code, optionalField))
}
function handleRequestFailure (err) {
if (isDone) return
if (busboy) {
req.unpipe(busboy)
busboy.destroy(err)
}
abortWithError(err, true)
}
req.on('error', function (err) {
handleRequestFailure(err || new Error('Request error'))
})
req.on('aborted', function () {
handleRequestFailure(new Error('Request aborted'))
})
req.on('close', function () {
if (req.readableEnded) return
handleRequestFailure(new Error('Request closed'))
})
try {
busboy = Busboy({
headers: req.headers,
limits: limits,
preservePath: preservePath,
defParamCharset: defParamCharset
})
} catch (err) {
return next(err)
}
appender = new FileAppender(fileStrategy, req)
// handle text field data
busboy.on('field', function (fieldname, value, { nameTruncated, valueTruncated }) {
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
if (nameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname)
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) {
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
}
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNestingDepth')) {
if (fieldname.split('[').length - 1 > limits.fieldNestingDepth) return abortWithCode('LIMIT_FIELD_NESTING', fieldname)
}
appendField(req.body, fieldname, value)
})
// handle files
busboy.on('file', function (fieldname, fileStream, { filename, encoding, mimeType }) {
var pendingWritesIncremented = false
fileStream.on('error', function (err) {
if (pendingWritesIncremented) {
pendingWrites.decrement()
}
abortWithError(err)
})
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
// don't attach to the files object, if there is no file
if (!filename) return fileStream.resume()
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) {
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY')
}
var file = {
fieldname: fieldname,
originalname: filename,
encoding: encoding,
mimetype: mimeType
}
var placeholder = appender.insertPlaceholder(file)
fileFilter(req, file, function (err, includeFile) {
if (errorOccured) {
appender.removePlaceholder(placeholder)
return fileStream.resume()
}
if (err) {
appender.removePlaceholder(placeholder)
return abortWithError(err)
}
if (!includeFile) {
appender.removePlaceholder(placeholder)
return fileStream.resume()
}
var aborting = false
pendingWritesIncremented = true
pendingWrites.increment()
Object.defineProperty(file, 'stream', {
configurable: true,
enumerable: false,
value: fileStream
})
fileStream.on('limit', function () {
aborting = true
abortWithCode('LIMIT_FILE_SIZE', fieldname)
})
pendingFiles.push(file)
storage._handleFile(req, file, function (err, info) {
var idx = pendingFiles.indexOf(file)
if (idx !== -1) pendingFiles.splice(idx, 1)
if (aborting) {
appender.removePlaceholder(placeholder)
uploadedFiles.push({ ...file, ...info })
return pendingWrites.decrement()
}
if (err) {
appender.removePlaceholder(placeholder)
pendingWrites.decrement()
return abortWithError(err)
}
var fileInfo = { ...file, ...info }
appender.replacePlaceholder(placeholder, fileInfo)
uploadedFiles.push(fileInfo)
pendingWrites.decrement()
indicateDone()
})
})
})
busboy.on('error', function (err) { abortWithError(err) })
busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') })
busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') })
busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') })
busboy.on('close', function () {
readFinished = true
indicateDone()
})
req.pipe(busboy)
}
}
module.exports = makeMiddleware
expressjs-multer-2e2af08/lib/multer-error.js 0000664 0000000 0000000 00000001311 15213763722 0021226 0 ustar 00root root 0000000 0000000 var util = require('util')
var errorMessages = {
LIMIT_PART_COUNT: 'Too many parts',
LIMIT_FILE_SIZE: 'File too large',
LIMIT_FILE_COUNT: 'Too many files',
LIMIT_FIELD_KEY: 'Field name too long',
LIMIT_FIELD_VALUE: 'Field value too long',
LIMIT_FIELD_COUNT: 'Too many fields',
LIMIT_UNEXPECTED_FILE: 'Unexpected field',
MISSING_FIELD_NAME: 'Field name missing',
LIMIT_FIELD_NESTING: 'Field name nesting too deep'
}
function MulterError (code, field) {
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = errorMessages[code]
this.code = code
if (field) this.field = field
}
util.inherits(MulterError, Error)
module.exports = MulterError
expressjs-multer-2e2af08/lib/remove-uploaded-files.js 0000664 0000000 0000000 00000001074 15213763722 0022765 0 ustar 00root root 0000000 0000000 function removeUploadedFiles (uploadedFiles, remove, cb) {
var length = uploadedFiles.length
var errors = []
if (length === 0) return cb(null, errors)
function handleFile (idx) {
var file = uploadedFiles[idx]
remove(file, function (err) {
if (err) {
err.file = file
err.field = file.fieldname
errors.push(err)
}
if (idx < length - 1) {
setImmediate(function () { handleFile(idx + 1) })
} else {
cb(null, errors)
}
})
}
handleFile(0)
}
module.exports = removeUploadedFiles
expressjs-multer-2e2af08/package.json 0000664 0000000 0000000 00000002544 15213763722 0017762 0 ustar 00root root 0000000 0000000 {
"name": "multer",
"description": "Middleware for handling `multipart/form-data`.",
"version": "2.2.0",
"contributors": [
"Hage Yaapa
(http://www.hacksparrow.com)",
"Jaret Pfluger ",
"Linus Unnebäck "
],
"license": "MIT",
"repository": "expressjs/multer",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
},
"keywords": [
"form",
"post",
"multipart",
"form-data",
"formdata",
"express",
"middleware"
],
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.6.0",
"concat-stream": "^2.0.0",
"type-is": "^1.6.18"
},
"devDependencies": {
"deep-equal": "^2.0.3",
"express": "^4.21.2",
"form-data": "^4.0.2",
"fs-temp": "^1.2.1",
"mocha": "^11.5.0",
"nyc": "^15.1.0",
"rimraf": "^2.4.1",
"standard": "^14.3.3",
"testdata-w3c-json-form": "^1.0.0"
},
"engines": {
"node": ">= 10.16.0"
},
"files": [
"LICENSE",
"index.js",
"storage/",
"lib/"
],
"scripts": {
"lint": "standard",
"lint:fix": "standard --fix",
"test": "mocha --reporter spec --exit --check-leaks test/",
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
"test-cov": "nyc --reporter=html --reporter=text npm test"
}
}
expressjs-multer-2e2af08/storage/ 0000775 0000000 0000000 00000000000 15213763722 0017133 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/storage/disk.js 0000664 0000000 0000000 00000003215 15213763722 0020424 0 ustar 00root root 0000000 0000000 var fs = require('fs')
var os = require('os')
var path = require('path')
var crypto = require('crypto')
function getFilename (req, file, cb) {
crypto.randomBytes(16, function (err, raw) {
cb(err, err ? undefined : raw.toString('hex'))
})
}
function getDestination (req, file, cb) {
cb(null, os.tmpdir())
}
function DiskStorage (opts) {
this.getFilename = (opts.filename || getFilename)
if (typeof opts.destination === 'string') {
fs.mkdirSync(opts.destination, { recursive: true })
this.getDestination = function ($0, $1, cb) { cb(null, opts.destination) }
} else {
this.getDestination = (opts.destination || getDestination)
}
}
DiskStorage.prototype._handleFile = function _handleFile (req, file, cb) {
var that = this
that.getDestination(req, file, function (err, destination) {
if (err) return cb(err)
that.getFilename(req, file, function (err, filename) {
if (err) return cb(err)
var finalPath = path.join(destination, filename)
if (file.stream.destroyed) return
var outStream = fs.createWriteStream(finalPath)
file.path = finalPath
file.stream.pipe(outStream)
outStream.on('error', cb)
outStream.on('finish', function () {
cb(null, {
destination: destination,
filename: filename,
path: finalPath,
size: outStream.bytesWritten
})
})
})
})
}
DiskStorage.prototype._removeFile = function _removeFile (req, file, cb) {
var path = file.path
delete file.destination
delete file.filename
delete file.path
fs.unlink(path, cb)
}
module.exports = function (opts) {
return new DiskStorage(opts)
}
expressjs-multer-2e2af08/storage/memory.js 0000664 0000000 0000000 00000000733 15213763722 0021004 0 ustar 00root root 0000000 0000000 var concat = require('concat-stream')
function MemoryStorage (opts) {}
MemoryStorage.prototype._handleFile = function _handleFile (req, file, cb) {
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
cb(null, {
buffer: data,
size: data.length
})
}))
}
MemoryStorage.prototype._removeFile = function _removeFile (req, file, cb) {
delete file.buffer
cb(null)
}
module.exports = function (opts) {
return new MemoryStorage(opts)
}
expressjs-multer-2e2af08/test/ 0000775 0000000 0000000 00000000000 15213763722 0016446 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/test/_util.js 0000664 0000000 0000000 00000001235 15213763722 0020121 0 ustar 00root root 0000000 0000000 var fs = require('fs')
var path = require('path')
var stream = require('stream')
exports.file = function file (name) {
return fs.createReadStream(path.join(__dirname, 'files', name))
}
exports.fileSize = function fileSize (path) {
return fs.statSync(path).size
}
exports.submitForm = function submitForm (multer, form, cb) {
form.getLength(function (err, length) {
if (err) return cb(err)
var req = new stream.PassThrough()
form.pipe(req)
req.headers = {
'content-type': 'multipart/form-data; boundary=' + form.getBoundary(),
'content-length': length
}
multer(req, null, function (err) {
cb(err, req)
})
})
}
expressjs-multer-2e2af08/test/async-file-filter-orphan.js 0000664 0000000 0000000 00000004144 15213763722 0023611 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var fs = require('fs')
var os = require('os')
var path = require('path')
var http = require('http')
var express = require('express')
var multer = require('../')
describe('async fileFilter cleanup', function () {
it('does not leave orphan files when request aborts with missing field name', function (done) {
var uploadDir = fs.mkdtempSync(path.join(os.tmpdir(), 'multer-orphan-'))
var app = express()
var upload = multer({
dest: uploadDir,
fileFilter: function (req, file, cb) {
setImmediate(function () { cb(null, true) })
}
})
app.post('/upload', upload.any(), function (req, res) {
res.json({ success: true })
})
app.use(function (err, req, res, next) {
res.status(400).json({ error: err.code })
})
var server = app.listen(0, function () {
var port = server.address().port
var boundary = 'TestBound'
var body =
'--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="f"; filename="a.bin"\r\n' +
'Content-Type: application/octet-stream\r\n\r\nORPHAN FILE DATA\r\n' +
'--' + boundary + '\r\n' +
'Content-Disposition: form-data; filename="b.bin"\r\n' +
'Content-Type: application/octet-stream\r\n\r\nx\r\n' +
'--' + boundary + '--\r\n'
var req = http.request({
hostname: 'localhost',
port: port,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': Buffer.byteLength(body)
}
}, function (res) {
res.resume()
res.on('end', function () {
setTimeout(function () {
var files = fs.readdirSync(uploadDir)
assert.strictEqual(res.statusCode, 400)
assert.strictEqual(files.length, 0)
server.close(done)
}, 500)
})
})
req.on('error', function (err) {
server.close(function () {
done(err)
})
})
req.write(body)
req.end()
})
})
}
)
expressjs-multer-2e2af08/test/def-param-charset.js 0000664 0000000 0000000 00000023175 15213763722 0022277 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var stream = require('stream')
var multer = require('../')
var temp = require('fs-temp')
var rimraf = require('rimraf')
describe('defParamCharset', function () {
var uploadDir, upload
beforeEach(function (done) {
temp.mkdir(function (err, path) {
if (err) return done(err)
var storage = multer.diskStorage({
destination: path,
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
uploadDir = path
upload = multer({ storage: storage })
done()
})
})
afterEach(function (done) {
rimraf(uploadDir, done)
})
it('should use latin1 as default charset for non-extended parameters', function (done) {
var req = new stream.PassThrough()
var boundary = 'AaB03x'
// Create a filename with latin1 characters (e.g., café encoded as latin1)
// In latin1: é = 0xE9
var bodyParts = [
'--' + boundary,
'Content-Disposition: form-data; name="testfile"; filename="caf',
'.txt"',
'Content-Type: text/plain',
'',
'test file content',
'--' + boundary + '--'
]
// Create buffer with proper latin1 encoding
var bodyBuffer = Buffer.concat([
Buffer.from(bodyParts[0] + '\r\n', 'ascii'),
Buffer.from(bodyParts[1], 'ascii'),
Buffer.from([0xE9]), // é in latin1
Buffer.from(bodyParts[2] + '\r\n', 'ascii'),
Buffer.from(bodyParts[3] + '\r\n', 'ascii'),
Buffer.from(bodyParts[4] + '\r\n', 'ascii'),
Buffer.from(bodyParts[5] + '\r\n', 'ascii'),
Buffer.from(bodyParts[6], 'ascii')
])
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': bodyBuffer.length
}
req.end(bodyBuffer)
upload.single('testfile')(req, null, function (err) {
assert.ifError(err)
// With latin1 (default), the filename should be interpreted as latin1
assert.strictEqual(req.file.originalname, 'café.txt')
assert.strictEqual(req.file.fieldname, 'testfile')
done()
})
})
it('should use custom charset when defParamCharset is specified', function (done) {
var customUpload = multer({
storage: multer.diskStorage({
destination: uploadDir,
filename: function (req, file, cb) {
cb(null, file.originalname)
}
}),
defParamCharset: 'utf8'
})
var req = new stream.PassThrough()
var boundary = 'AaB03x'
// Create a filename with UTF-8 characters (e.g., café encoded as UTF-8)
// In UTF-8: é = 0xC3 0xA9
var bodyParts = [
'--' + boundary,
'Content-Disposition: form-data; name="testfile"; filename="caf',
'.txt"',
'Content-Type: text/plain',
'',
'test file content',
'--' + boundary + '--'
]
// Create buffer with proper UTF-8 encoding
var bodyBuffer = Buffer.concat([
Buffer.from(bodyParts[0] + '\r\n', 'ascii'),
Buffer.from(bodyParts[1], 'ascii'),
Buffer.from([0xC3, 0xA9]), // é in UTF-8
Buffer.from(bodyParts[2] + '\r\n', 'ascii'),
Buffer.from(bodyParts[3] + '\r\n', 'ascii'),
Buffer.from(bodyParts[4] + '\r\n', 'ascii'),
Buffer.from(bodyParts[5] + '\r\n', 'ascii'),
Buffer.from(bodyParts[6], 'ascii')
])
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': bodyBuffer.length
}
req.end(bodyBuffer)
customUpload.single('testfile')(req, null, function (err) {
assert.ifError(err)
// With utf8, the filename should be interpreted as utf8
assert.strictEqual(req.file.originalname, 'café.txt')
assert.strictEqual(req.file.fieldname, 'testfile')
done()
})
})
it('should not affect extended parameters with explicit charset', function (done) {
var customUpload = multer({
storage: multer.diskStorage({
destination: uploadDir,
filename: function (req, file, cb) {
cb(null, file.originalname)
}
}),
defParamCharset: 'ascii' // This should be ignored for extended parameters
})
var req = new stream.PassThrough()
var boundary = 'AaB03x'
var body = [
'--' + boundary,
// Extended parameter with explicit UTF-8 charset should override defParamCharset
'Content-Disposition: form-data; name="testfile"; filename*=utf-8\'\'caf%C3%A9.txt',
'Content-Type: text/plain',
'',
'test file content',
'--' + boundary + '--'
].join('\r\n')
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
req.end(body)
customUpload.single('testfile')(req, null, function (err) {
assert.ifError(err)
// Extended parameter should use its own charset (UTF-8), not defParamCharset
assert.strictEqual(req.file.originalname, 'café.txt')
assert.strictEqual(req.file.fieldname, 'testfile')
done()
})
})
it('should handle different charsets correctly', function (done) {
var customUpload = multer({
storage: multer.diskStorage({
destination: uploadDir,
filename: function (req, file, cb) {
cb(null, file.originalname)
}
}),
defParamCharset: 'iso-8859-1' // Same as latin1
})
var req = new stream.PassThrough()
var boundary = 'AaB03x'
// Test with ISO-8859-1 encoded characters
var bodyParts = [
'--' + boundary,
'Content-Disposition: form-data; name="testfile"; filename="test',
'.txt"',
'Content-Type: text/plain',
'',
'test file content',
'--' + boundary + '--'
]
// Create buffer with proper ISO-8859-1 encoding
var bodyBuffer = Buffer.concat([
Buffer.from(bodyParts[0] + '\r\n', 'ascii'),
Buffer.from(bodyParts[1], 'ascii'),
Buffer.from([0xF1]), // ñ in ISO-8859-1
Buffer.from(bodyParts[2] + '\r\n', 'ascii'),
Buffer.from(bodyParts[3] + '\r\n', 'ascii'),
Buffer.from(bodyParts[4] + '\r\n', 'ascii'),
Buffer.from(bodyParts[5] + '\r\n', 'ascii'),
Buffer.from(bodyParts[6], 'ascii')
])
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': bodyBuffer.length
}
req.end(bodyBuffer)
customUpload.single('testfile')(req, null, function (err) {
assert.ifError(err)
// Should correctly decode the ñ character
assert.strictEqual(req.file.originalname, 'testñ.txt')
assert.strictEqual(req.file.fieldname, 'testfile')
done()
})
})
it('should work with memory storage', function (done) {
var memoryUpload = multer({
storage: multer.memoryStorage(),
defParamCharset: 'utf8'
})
var req = new stream.PassThrough()
var boundary = 'AaB03x'
var bodyParts = [
'--' + boundary,
'Content-Disposition: form-data; name="testfile"; filename="test',
'.txt"',
'Content-Type: text/plain',
'',
'test file content',
'--' + boundary + '--'
]
// Create buffer with proper UTF-8 encoding
var bodyBuffer = Buffer.concat([
Buffer.from(bodyParts[0] + '\r\n', 'ascii'),
Buffer.from(bodyParts[1], 'ascii'),
Buffer.from([0xC3, 0xA9]), // é in UTF-8
Buffer.from(bodyParts[2] + '\r\n', 'ascii'),
Buffer.from(bodyParts[3] + '\r\n', 'ascii'),
Buffer.from(bodyParts[4] + '\r\n', 'ascii'),
Buffer.from(bodyParts[5] + '\r\n', 'ascii'),
Buffer.from(bodyParts[6], 'ascii')
])
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': bodyBuffer.length
}
req.end(bodyBuffer)
memoryUpload.single('testfile')(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(req.file.originalname, 'testé.txt')
assert.strictEqual(req.file.fieldname, 'testfile')
assert.ok(Buffer.isBuffer(req.file.buffer))
done()
})
})
it('should work with array uploads', function (done) {
var customUpload = multer({
storage: multer.diskStorage({
destination: uploadDir,
filename: function (req, file, cb) {
cb(null, file.originalname)
}
}),
defParamCharset: 'utf8'
})
var req = new stream.PassThrough()
var boundary = 'AaB03x'
// Create buffer with proper UTF-8 encoding for both files
var bodyBuffer = Buffer.concat([
Buffer.from('--' + boundary + '\r\n', 'ascii'),
Buffer.from('Content-Disposition: form-data; name="testfiles"; filename="file1', 'ascii'),
Buffer.from([0xC3, 0xA9]), // é in UTF-8
Buffer.from('.txt"\r\n', 'ascii'),
Buffer.from('Content-Type: text/plain\r\n', 'ascii'),
Buffer.from('\r\n', 'ascii'),
Buffer.from('test file 1 content\r\n', 'ascii'),
Buffer.from('--' + boundary + '\r\n', 'ascii'),
Buffer.from('Content-Disposition: form-data; name="testfiles"; filename="file2', 'ascii'),
Buffer.from([0xC3, 0xB1]), // ñ in UTF-8
Buffer.from('.txt"\r\n', 'ascii'),
Buffer.from('Content-Type: text/plain\r\n', 'ascii'),
Buffer.from('\r\n', 'ascii'),
Buffer.from('test file 2 content\r\n', 'ascii'),
Buffer.from('--' + boundary + '--', 'ascii')
])
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': bodyBuffer.length
}
req.end(bodyBuffer)
customUpload.array('testfiles', 2)(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(req.files.length, 2)
assert.strictEqual(req.files[0].originalname, 'file1é.txt')
assert.strictEqual(req.files[1].originalname, 'file2ñ.txt')
done()
})
})
})
expressjs-multer-2e2af08/test/disk-storage.js 0000664 0000000 0000000 00000014247 15213763722 0021410 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var deepEqual = require('deep-equal')
var fs = require('fs')
var path = require('path')
var util = require('./_util')
var multer = require('../')
var temp = require('fs-temp')
var rimraf = require('rimraf')
var FormData = require('form-data')
describe('Disk Storage', function () {
var uploadDir, upload
beforeEach(function (done) {
temp.mkdir(function (err, path) {
if (err) return done(err)
uploadDir = path
upload = multer({ dest: path })
done()
})
})
afterEach(function (done) {
rimraf(uploadDir, done)
})
it('should process parser/form-data POST request', function (done) {
var form = new FormData()
var parser = upload.single('small0')
form.append('name', 'Multer')
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.body.name, 'Multer')
assert.strictEqual(req.file.fieldname, 'small0')
assert.strictEqual(req.file.originalname, 'small0.dat')
assert.strictEqual(req.file.size, 1778)
assert.strictEqual(util.fileSize(req.file.path), 1778)
done()
})
})
it('should process empty fields and an empty file', function (done) {
var form = new FormData()
var parser = upload.single('empty')
form.append('empty', util.file('empty.dat'))
form.append('name', 'Multer')
form.append('version', '')
form.append('year', '')
form.append('checkboxfull', 'cb1')
form.append('checkboxfull', 'cb2')
form.append('checkboxhalfempty', 'cb1')
form.append('checkboxhalfempty', '')
form.append('checkboxempty', '')
form.append('checkboxempty', '')
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.body.name, 'Multer')
assert.strictEqual(req.body.version, '')
assert.strictEqual(req.body.year, '')
assert(deepEqual(req.body.checkboxfull, ['cb1', 'cb2']))
assert(deepEqual(req.body.checkboxhalfempty, ['cb1', '']))
assert(deepEqual(req.body.checkboxempty, ['', '']))
assert.strictEqual(req.file.fieldname, 'empty')
assert.strictEqual(req.file.originalname, 'empty.dat')
assert.strictEqual(req.file.size, 0)
assert.strictEqual(util.fileSize(req.file.path), 0)
done()
})
})
it('should process multiple files', function (done) {
var form = new FormData()
var parser = upload.fields([
{ name: 'empty', maxCount: 1 },
{ name: 'tiny0', maxCount: 1 },
{ name: 'tiny1', maxCount: 1 },
{ name: 'small0', maxCount: 1 },
{ name: 'small1', maxCount: 1 },
{ name: 'medium', maxCount: 1 },
{ name: 'large', maxCount: 1 }
])
form.append('empty', util.file('empty.dat'))
form.append('tiny0', util.file('tiny0.dat'))
form.append('tiny1', util.file('tiny1.dat'))
form.append('small0', util.file('small0.dat'))
form.append('small1', util.file('small1.dat'))
form.append('medium', util.file('medium.dat'))
form.append('large', util.file('large.jpg'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert(deepEqual(req.body, {}))
assert.strictEqual(req.files.empty[0].fieldname, 'empty')
assert.strictEqual(req.files.empty[0].originalname, 'empty.dat')
assert.strictEqual(req.files.empty[0].size, 0)
assert.strictEqual(util.fileSize(req.files.empty[0].path), 0)
assert.strictEqual(req.files.tiny0[0].fieldname, 'tiny0')
assert.strictEqual(req.files.tiny0[0].originalname, 'tiny0.dat')
assert.strictEqual(req.files.tiny0[0].size, 122)
assert.strictEqual(util.fileSize(req.files.tiny0[0].path), 122)
assert.strictEqual(req.files.tiny1[0].fieldname, 'tiny1')
assert.strictEqual(req.files.tiny1[0].originalname, 'tiny1.dat')
assert.strictEqual(req.files.tiny1[0].size, 7)
assert.strictEqual(util.fileSize(req.files.tiny1[0].path), 7)
assert.strictEqual(req.files.small0[0].fieldname, 'small0')
assert.strictEqual(req.files.small0[0].originalname, 'small0.dat')
assert.strictEqual(req.files.small0[0].size, 1778)
assert.strictEqual(util.fileSize(req.files.small0[0].path), 1778)
assert.strictEqual(req.files.small1[0].fieldname, 'small1')
assert.strictEqual(req.files.small1[0].originalname, 'small1.dat')
assert.strictEqual(req.files.small1[0].size, 315)
assert.strictEqual(util.fileSize(req.files.small1[0].path), 315)
assert.strictEqual(req.files.medium[0].fieldname, 'medium')
assert.strictEqual(req.files.medium[0].originalname, 'medium.dat')
assert.strictEqual(req.files.medium[0].size, 13196)
assert.strictEqual(util.fileSize(req.files.medium[0].path), 13196)
assert.strictEqual(req.files.large[0].fieldname, 'large')
assert.strictEqual(req.files.large[0].originalname, 'large.jpg')
assert.strictEqual(req.files.large[0].size, 2413677)
assert.strictEqual(util.fileSize(req.files.large[0].path), 2413677)
done()
})
})
it('should remove uploaded files on error', function (done) {
var form = new FormData()
var parser = upload.single('tiny0')
form.append('tiny0', util.file('tiny0.dat'))
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'small0')
assert(deepEqual(err.storageErrors, []))
var files = fs.readdirSync(uploadDir)
assert(deepEqual(files, []))
done()
})
})
it('should report error when directory doesn\'t exist', function (done) {
var directory = path.join(temp.mkdirSync(), 'ghost')
function dest ($0, $1, cb) { cb(null, directory) }
var storage = multer.diskStorage({ destination: dest })
var upload = multer({ storage: storage })
var parser = upload.single('tiny0')
var form = new FormData()
form.append('tiny0', util.file('tiny0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'ENOENT')
assert.strictEqual(path.dirname(err.path), directory)
done()
})
})
})
expressjs-multer-2e2af08/test/error-handling.js 0000664 0000000 0000000 00000031640 15213763722 0021723 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var os = require('os')
var util = require('./_util')
var multer = require('../')
var removeUploadedFiles = require('../lib/remove-uploaded-files')
var stream = require('stream')
var FormData = require('form-data')
var http = require('http')
var net = require('net')
function withLimits (limits, fields) {
var storage = multer.memoryStorage()
return multer({ storage: storage, limits: limits }).fields(fields)
}
describe('Error Handling', function () {
it('should be an instance of both `Error` and `MulterError` classes in case of the Multer\'s error', function (done) {
var form = new FormData()
var storage = multer.diskStorage({ destination: os.tmpdir() })
var upload = multer({ storage: storage }).fields([
{ name: 'small0', maxCount: 1 }
])
form.append('small0', util.file('small0.dat'))
form.append('small0', util.file('small0.dat'))
util.submitForm(upload, form, function (err, req) {
assert.strictEqual(err instanceof Error, true)
assert.strictEqual(err instanceof multer.MulterError, true)
done()
})
})
it('should respect parts limit', function (done) {
var form = new FormData()
var parser = withLimits({ parts: 1 }, [
{ name: 'small0', maxCount: 1 }
])
form.append('field0', 'BOOM!')
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_PART_COUNT')
done()
})
})
it('should respect file size limit', function (done) {
var form = new FormData()
var parser = withLimits({ fileSize: 1500 }, [
{ name: 'tiny0', maxCount: 1 },
{ name: 'small0', maxCount: 1 }
])
form.append('tiny0', util.file('tiny0.dat'))
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FILE_SIZE')
assert.strictEqual(err.field, 'small0')
done()
})
})
it('should respect file count limit', function (done) {
var form = new FormData()
var parser = withLimits({ files: 1 }, [
{ name: 'small0', maxCount: 1 },
{ name: 'small1', maxCount: 1 }
])
form.append('small0', util.file('small0.dat'))
form.append('small1', util.file('small1.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FILE_COUNT')
done()
})
})
it('should respect file key limit', function (done) {
var form = new FormData()
var parser = withLimits({ fieldNameSize: 4 }, [
{ name: 'small0', maxCount: 1 }
])
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FIELD_KEY')
done()
})
})
it('should respect field key limit', function (done) {
var form = new FormData()
var parser = withLimits({ fieldNameSize: 4 }, [])
form.append('ok', 'SMILE')
form.append('blowup', 'BOOM!')
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FIELD_KEY')
done()
})
})
it('should respect field value limit', function (done) {
var form = new FormData()
var parser = withLimits({ fieldSize: 16 }, [])
form.append('field0', 'This is okay')
form.append('field1', 'This will make the parser explode')
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FIELD_VALUE')
assert.strictEqual(err.field, 'field1')
done()
})
})
it('should respect field count limit', function (done) {
var form = new FormData()
var parser = withLimits({ fields: 1 }, [])
form.append('field0', 'BOOM!')
form.append('field1', 'BOOM!')
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FIELD_COUNT')
done()
})
})
it('should respect fields given', function (done) {
var form = new FormData()
var parser = withLimits(undefined, [
{ name: 'wrongname', maxCount: 1 }
])
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'small0')
done()
})
})
it('should notify of missing field name', function (done) {
var req = new stream.PassThrough()
var storage = multer.memoryStorage()
var upload = multer({ storage: storage }).single('tiny0')
var boundary = 'AaB03x'
var body = [
'--' + boundary,
'Content-Disposition: form-data',
'',
'test content',
'--' + boundary,
''
].join('\r\n')
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
req.end(body)
upload(req, null, function (err) {
assert.strictEqual(err.code, 'MISSING_FIELD_NAME')
done()
})
})
it('should notify of missing field name', function (done) {
var form = new FormData()
var storage = multer.memoryStorage()
var parser = multer({ storage: storage }).single('small0')
form.append('', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'MISSING_FIELD_NAME')
done()
})
})
it('should report errors from storage engines', function (done) {
var storage = multer.memoryStorage()
storage._removeFile = function _removeFile (req, file, cb) {
var err = new Error('Test error')
err.code = 'TEST'
cb(err)
}
var form = new FormData()
var upload = multer({ storage: storage })
var parser = upload.single('tiny0')
form.append('tiny0', util.file('tiny0.dat'))
form.append('small0', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'small0')
assert.strictEqual(err.storageErrors.length, 1)
assert.strictEqual(err.storageErrors[0].code, 'TEST')
assert.strictEqual(err.storageErrors[0].field, 'tiny0')
assert.strictEqual(err.storageErrors[0].file, req.file)
done()
})
})
it('should report errors from busboy constructor', function (done) {
var req = new stream.PassThrough()
var storage = multer.memoryStorage()
var upload = multer({ storage: storage }).single('tiny0')
var body = 'test'
req.headers = {
'content-type': 'multipart/form-data',
'content-length': body.length
}
req.end(body)
upload(req, null, function (err) {
assert.strictEqual(err.message, 'Multipart: Boundary not found')
done()
})
})
it('should report errors from busboy parsing', function (done) {
var req = new stream.PassThrough()
var storage = multer.memoryStorage()
var upload = multer({ storage: storage }).single('tiny0')
var boundary = 'AaB03x'
var body = [
'--' + boundary,
'Content-Disposition: form-data; name="tiny0"; filename="test.txt"',
'Content-Type: text/plain',
'',
'test without end boundary'
].join('\r\n')
req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
req.end(body)
upload(req, null, function (err) {
assert.strictEqual(err.message, 'Unexpected end of form')
done()
})
})
it('should gracefully handle more than one error at a time', function (done) {
var form = new FormData()
var storage = multer.diskStorage({ destination: os.tmpdir() })
var upload = multer({ storage: storage, limits: { fileSize: 1, files: 1 } }).fields([
{ name: 'small0', maxCount: 1 }
])
form.append('small0', util.file('small0.dat'))
form.append('small0', util.file('small0.dat'))
util.submitForm(upload, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_FILE_SIZE')
done()
})
})
it('should allow client to finish sending body before error response', function (done) {
this.timeout(10000)
var upload = multer({ storage: multer.memoryStorage() }).single('expected')
var server = http.createServer(function (req, res) {
upload(req, res, function (err) {
res.statusCode = err ? 500 : 200
res.end(err ? err.code : 'OK')
})
})
server.listen(0, function () {
var port = server.address().port
var boundary = 'Drain' + Date.now()
var preamble = [
'--' + boundary,
'Content-Disposition: form-data; name="unexpected"; filename="test.bin"',
'Content-Type: application/octet-stream',
'',
''
].join('\r\n')
var footer = '\r\n--' + boundary + '--\r\n'
var chunk = Buffer.alloc(32 * 1024, 97)
var totalChunks = 24
var contentLength = Buffer.byteLength(preamble) +
(chunk.length * totalChunks) +
Buffer.byteLength(footer)
var sock = new net.Socket()
var socketError = null
var response = ''
var sentChunks = 0
var finished = false
var timeout = setTimeout(function () {
if (finished) return
finished = true
sock.destroy()
server.close(function () {
done(new Error('timed out while uploading request body'))
})
}, 8000)
function finish (err) {
if (finished) return
finished = true
clearTimeout(timeout)
server.close(function () {
done(err)
})
}
function writeChunk () {
if (sentChunks >= totalChunks) {
sock.write(footer)
return
}
sentChunks += 1
var canContinue = sock.write(chunk)
if (canContinue) {
setTimeout(writeChunk, 2)
} else {
sock.once('drain', function () {
setTimeout(writeChunk, 2)
})
}
}
sock.connect(port, '127.0.0.1', function () {
sock.write(
'POST / HTTP/1.1\r\n' +
'Host: localhost\r\n' +
'Connection: close\r\n' +
'Content-Type: multipart/form-data; boundary=' + boundary + '\r\n' +
'Content-Length: ' + contentLength + '\r\n\r\n'
)
sock.write(preamble)
writeChunk()
})
sock.on('data', function (buf) {
response += buf.toString('utf8')
})
sock.on('error', function (err) {
socketError = err
})
sock.on('close', function () {
if (socketError) return finish(socketError)
try {
assert.strictEqual(sentChunks, totalChunks)
assert.ok(/HTTP\/1\.1 500/.test(response))
finish()
} catch (err) {
finish(err)
}
})
})
})
it('should not hang when client aborts multipart upload', function (done) {
this.timeout(5000)
var upload = multer({ storage: multer.memoryStorage() }).any()
var server = http.createServer(function (req, res) {
var hung = false
var timer = setTimeout(function () {
hung = true
server.close()
done(new Error('Middleware hung when client aborted request'))
}, 1000)
upload(req, res, function (/* err */) {
if (hung) return
clearTimeout(timer)
server.close()
done()
})
})
server.listen(0, function () {
var port = server.address().port
var boundary = 'PoC' + Date.now()
var sock = new net.Socket()
sock.connect(port, '127.0.0.1', function () {
sock.write(
'POST / HTTP/1.1\r\n' +
'Host: localhost\r\n' +
'Content-Type: multipart/form-data; boundary=' + boundary + '\r\n' +
'Content-Length: 999999\r\n\r\n' +
'--' + boundary + '\r\n' +
'Content-Disposition: form-data; name="file"; filename="test.bin"\r\n' +
'Content-Type: application/octet-stream\r\n\r\n' +
'AAAAAAAAAAAAAAAA'
)
setTimeout(function () {
sock.destroy()
}, 50)
})
sock.on('error', function () {})
})
})
it('should not overflow call stack when cleaning up many files (memory storage sync remove)', function (done) {
// - without setImmediate in remove-uploaded-files, synchronous _removeFile (e.g. memory storage)
// causes handleFile(0) -> remove -> cb() -> handleFile(1) -> ... in one stack,
// leading to "Maximum call stack size exceeded"
// - use enough files to exceed typical node stack depth (~10k - 30k)
this.timeout(10 * 1000)
var fileCount = 25000
var uploadedFiles = []
for (var i = 0; i < fileCount; i++) {
uploadedFiles.push({ fieldname: 'file', originalname: 'f.dat', buffer: Buffer.alloc(0) })
}
function syncRemove (file, cb) {
delete file.buffer
cb(null)
}
removeUploadedFiles(uploadedFiles, syncRemove, function (err, errors) {
assert.ifError(err)
assert.strictEqual(errors.length, 0)
done()
})
})
})
expressjs-multer-2e2af08/test/expected-files.js 0000664 0000000 0000000 00000006313 15213763722 0021710 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var util = require('./_util')
var multer = require('../')
var FormData = require('form-data')
describe('Expected files', function () {
var upload
before(function (done) {
upload = multer()
done()
})
it('should reject single unexpected file', function (done) {
var form = new FormData()
var parser = upload.single('butme')
form.append('notme', util.file('small0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'notme')
done()
})
})
it('should reject array of multiple files', function (done) {
var form = new FormData()
var parser = upload.array('butme', 4)
form.append('notme', util.file('small0.dat'))
form.append('notme', util.file('small1.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'notme')
done()
})
})
it('should reject overflowing arrays', function (done) {
var form = new FormData()
var parser = upload.array('butme', 1)
form.append('butme', util.file('small0.dat'))
form.append('butme', util.file('small1.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'butme')
done()
})
})
it('should accept files with expected fieldname', function (done) {
var form = new FormData()
var parser = upload.fields([
{ name: 'butme', maxCount: 2 },
{ name: 'andme', maxCount: 2 }
])
form.append('butme', util.file('small0.dat'))
form.append('butme', util.file('small1.dat'))
form.append('andme', util.file('empty.dat'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.files.butme.length, 2)
assert.strictEqual(req.files.andme.length, 1)
done()
})
})
it('should reject files with unexpected fieldname', function (done) {
var form = new FormData()
var parser = upload.fields([
{ name: 'butme', maxCount: 2 },
{ name: 'andme', maxCount: 2 }
])
form.append('butme', util.file('small0.dat'))
form.append('butme', util.file('small1.dat'))
form.append('andme', util.file('empty.dat'))
form.append('notme', util.file('empty.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.code, 'LIMIT_UNEXPECTED_FILE')
assert.strictEqual(err.field, 'notme')
done()
})
})
it('should allow any file to come thru', function (done) {
var form = new FormData()
var parser = upload.any()
form.append('butme', util.file('small0.dat'))
form.append('butme', util.file('small1.dat'))
form.append('andme', util.file('empty.dat'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.files.length, 3)
assert.strictEqual(req.files[0].fieldname, 'butme')
assert.strictEqual(req.files[1].fieldname, 'butme')
assert.strictEqual(req.files[2].fieldname, 'andme')
done()
})
})
})
expressjs-multer-2e2af08/test/express-integration.js 0000664 0000000 0000000 00000014023 15213763722 0023016 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var http = require('http')
var multer = require('../')
var util = require('./_util')
var express = require('express')
var FormData = require('form-data')
var concat = require('concat-stream')
var port = 34279
describe('Express Integration', function () {
var app
before(function (done) {
app = express()
app.listen(port, done)
})
function submitForm (form, path, cb) {
var req = form.submit('http://localhost:' + port + path)
req.on('error', cb)
req.on('response', function (res) {
res.on('error', cb)
res.pipe(concat({ encoding: 'buffer' }, function (body) {
cb(null, res, body)
}))
})
}
it('should work with express error handling', function (done) {
var limits = { fileSize: 200 }
var upload = multer({ limits: limits })
var router = new express.Router()
var form = new FormData()
var routeCalled = 0
var errorCalled = 0
form.append('avatar', util.file('large.jpg'))
router.post('/profile', upload.single('avatar'), function (req, res, next) {
routeCalled++
res.status(200).end('SUCCESS')
})
router.use(function (err, req, res, next) {
assert.strictEqual(err.code, 'LIMIT_FILE_SIZE')
errorCalled++
res.status(500).end('ERROR')
})
app.use('/t1', router)
submitForm(form, '/t1/profile', function (err, res, body) {
assert.ifError(err)
assert.strictEqual(routeCalled, 0)
assert.strictEqual(errorCalled, 1)
assert.strictEqual(body.toString(), 'ERROR')
assert.strictEqual(res.statusCode, 500)
done()
})
})
it('should work when receiving error from fileFilter', function (done) {
function fileFilter (req, file, cb) {
cb(new Error('TEST'))
}
var upload = multer({ fileFilter: fileFilter })
var router = new express.Router()
var form = new FormData()
var routeCalled = 0
var errorCalled = 0
form.append('avatar', util.file('large.jpg'))
router.post('/profile', upload.single('avatar'), function (req, res, next) {
routeCalled++
res.status(200).end('SUCCESS')
})
router.use(function (err, req, res, next) {
assert.strictEqual(err.message, 'TEST')
errorCalled++
res.status(500).end('ERROR')
})
app.use('/t2', router)
submitForm(form, '/t2/profile', function (err, res, body) {
assert.ifError(err)
assert.strictEqual(routeCalled, 0)
assert.strictEqual(errorCalled, 1)
assert.strictEqual(body.toString(), 'ERROR')
assert.strictEqual(res.statusCode, 500)
done()
})
})
it('should not crash on malformed request', function (done) {
var upload = multer()
app.post('/upload', upload.single('file'), function (req, res) {
res.status(500).end('Request should not be processed')
})
app.use(function (err, req, res, next) {
assert.strictEqual(err.message, 'Unexpected end of form')
res.status(200).end('Correct error')
})
var boundary = 'AaB03x'
var body = [
'--' + boundary,
'Content-Disposition: form-data; name="file"; filename="test.txt"',
'Content-Type: text/plain',
'',
'test without end boundary'
].join('\r\n')
var options = {
hostname: 'localhost',
port,
path: '/upload',
method: 'POST',
headers: {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
}
var req = http.request(options, (res) => {
assert.strictEqual(res.statusCode, 200)
done()
})
req.on('error', (err) => {
done(err)
})
req.write(body)
req.end()
})
it('should not crash on malformed request that causes two errors to be emitted by busboy', function (done) {
var upload = multer()
app.post('/upload2', upload.single('file'), function (req, res) {
res.status(500).end('Request should not be processed')
})
app.use(function (err, req, res, next) {
assert.strictEqual(err.message, 'Malformed part header')
res.status(200).end('Correct error')
})
var boundary = 'AaB03x'
// this payload causes two errors to be emitted by busboy: `Malformed part header` and `Unexpected end of form`
var body = [
'--' + boundary,
'Content-Disposition: form-data; name="file"; filename="test.txt"',
'Content-Type: text/plain',
'',
'--' + boundary + '--',
''
].join('\r\n')
var options = {
hostname: 'localhost',
port,
path: '/upload2',
method: 'POST',
headers: {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}
}
var req = http.request(options, (res) => {
assert.strictEqual(res.statusCode, 200)
done()
})
req.on('error', (err) => {
done(err)
})
req.write(body)
req.end()
})
it('should not crash on malformed multipart body with bad boundary', function (done) {
var upload = multer()
app.post('/upload3', upload.single('image'), function (req, res) {
res.status(500).end('Request should not be processed')
})
app.use(function (err, req, res, next) {
assert.strictEqual(err.message, 'Unexpected end of form')
res.status(200).end('Correct error')
})
var boundary = '----FormBoundary'
var body = [
'------FormBoundary',
'Content-Disposition: form-data; name="image"; filename=""',
'Content-Type: application/octet-stream',
'',
'', // empty content
'------FormBoundar' // intentionally malformed final boundary (missing 'y')
].join('\r\n')
var options = {
hostname: 'localhost',
port,
path: '/upload3',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': Buffer.byteLength(body)
}
}
var req = http.request(options, (res) => {
assert.strictEqual(res.statusCode, 200)
done()
})
req.write(body)
req.end()
})
})
expressjs-multer-2e2af08/test/fields.js 0000664 0000000 0000000 00000006506 15213763722 0020261 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var deepEqual = require('deep-equal')
var stream = require('stream')
var util = require('./_util')
var multer = require('../')
var FormData = require('form-data')
var testData = require('testdata-w3c-json-form')
describe('Fields', function () {
var parser
before(function () {
parser = multer().fields([])
})
it('should process multiple fields', function (done) {
var form = new FormData()
form.append('name', 'Multer')
form.append('key', 'value')
form.append('abc', 'xyz')
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert(deepEqual(req.body, {
name: 'Multer',
key: 'value',
abc: 'xyz'
}))
done()
})
})
it('should process empty fields', function (done) {
var form = new FormData()
form.append('name', 'Multer')
form.append('key', '')
form.append('abc', '')
form.append('checkboxfull', 'cb1')
form.append('checkboxfull', 'cb2')
form.append('checkboxhalfempty', 'cb1')
form.append('checkboxhalfempty', '')
form.append('checkboxempty', '')
form.append('checkboxempty', '')
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert(deepEqual(req.body, {
name: 'Multer',
key: '',
abc: '',
checkboxfull: ['cb1', 'cb2'],
checkboxhalfempty: ['cb1', ''],
checkboxempty: ['', '']
}))
done()
})
})
it('should not process non-multipart POST request', function (done) {
var req = new stream.PassThrough()
req.end('name=Multer')
req.method = 'POST'
req.headers = {
'content-type': 'application/x-www-form-urlencoded',
'content-length': 11
}
parser(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(Object.prototype.hasOwnProperty.call(req, 'body'), false)
assert.strictEqual(Object.prototype.hasOwnProperty.call(req, 'files'), false)
done()
})
})
it('should not process non-multipart GET request', function (done) {
var req = new stream.PassThrough()
req.end('name=Multer')
req.method = 'GET'
req.headers = {
'content-type': 'application/x-www-form-urlencoded',
'content-length': 11
}
parser(req, null, function (err) {
assert.ifError(err)
assert.strictEqual(Object.prototype.hasOwnProperty.call(req, 'body'), false)
assert.strictEqual(Object.prototype.hasOwnProperty.call(req, 'files'), false)
done()
})
})
testData.forEach(function (test) {
it('should handle ' + test.name, function (done) {
var form = new FormData()
test.fields.forEach(function (field) {
form.append(field.key, field.value)
})
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert(deepEqual(req.body, test.expected))
done()
})
})
})
it('should convert arrays into objects', function (done) {
var form = new FormData()
form.append('obj[0]', 'a')
form.append('obj[2]', 'c')
form.append('obj[x]', 'yz')
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert(deepEqual(req.body, {
obj: {
0: 'a',
2: 'c',
x: 'yz'
}
}))
done()
})
})
})
expressjs-multer-2e2af08/test/file-filter.js 0000664 0000000 0000000 00000003013 15213763722 0021203 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var util = require('./_util')
var multer = require('../')
var FormData = require('form-data')
function withFilter (fileFilter) {
return multer({ fileFilter: fileFilter })
}
function skipSpecificFile (req, file, cb) {
cb(null, file.fieldname !== 'notme')
}
function reportFakeError (req, file, cb) {
cb(new Error('Fake error'))
}
describe('File Filter', function () {
it('should skip some files', function (done) {
var form = new FormData()
var upload = withFilter(skipSpecificFile)
var parser = upload.fields([
{ name: 'notme', maxCount: 1 },
{ name: 'butme', maxCount: 1 }
])
form.append('notme', util.file('tiny0.dat'))
form.append('butme', util.file('tiny1.dat'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.files.notme, undefined)
assert.strictEqual(req.files.butme[0].fieldname, 'butme')
assert.strictEqual(req.files.butme[0].originalname, 'tiny1.dat')
assert.strictEqual(req.files.butme[0].size, 7)
assert.strictEqual(req.files.butme[0].buffer.length, 7)
done()
})
})
it('should report errors from fileFilter', function (done) {
var form = new FormData()
var upload = withFilter(reportFakeError)
var parser = upload.single('test')
form.append('test', util.file('tiny0.dat'))
util.submitForm(parser, form, function (err, req) {
assert.strictEqual(err.message, 'Fake error')
done()
})
})
})
expressjs-multer-2e2af08/test/file-ordering.js 0000664 0000000 0000000 00000002423 15213763722 0021533 0 ustar 00root root 0000000 0000000 /* eslint-env mocha */
var assert = require('assert')
var util = require('./_util')
var multer = require('../')
var FormData = require('form-data')
describe('File ordering', function () {
it('should present files in same order as they came', function (done) {
var storage = multer.memoryStorage()
var upload = multer({ storage: storage })
var parser = upload.array('themFiles', 2)
var i = 0
var calls = [{}, {}]
var pending = 2
var _handleFile = storage._handleFile
storage._handleFile = function (req, file, cb) {
var id = (i++)
_handleFile.call(this, req, file, function (err, info) {
if (err) return cb(err)
calls[id].cb = cb
calls[id].info = info
if (--pending === 0) {
calls[1].cb(null, calls[1].info)
calls[0].cb(null, calls[0].info)
}
})
}
var form = new FormData()
form.append('themFiles', util.file('small0.dat'))
form.append('themFiles', util.file('small1.dat'))
util.submitForm(parser, form, function (err, req) {
assert.ifError(err)
assert.strictEqual(req.files.length, 2)
assert.strictEqual(req.files[0].originalname, 'small0.dat')
assert.strictEqual(req.files[1].originalname, 'small1.dat')
done()
})
})
})
expressjs-multer-2e2af08/test/files/ 0000775 0000000 0000000 00000000000 15213763722 0017550 5 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/test/files/empty.dat 0000664 0000000 0000000 00000000000 15213763722 0021366 0 ustar 00root root 0000000 0000000 expressjs-multer-2e2af08/test/files/large.jpg 0000664 0000000 0000000 00011152155 15213763722 0021357 0 ustar 00root root 0000000 0000000 ÿØÿáÆExif II* † Œ ¤ ¬ ( 2 ´ È i‡ ø Canon Canon EOS 400D DIGITAL H H 2008:07:04 13:02:14 ÿ € ÿ € ÿ š‚ B �‚ J "ˆ ð
'ˆ
� 0220� R � f ‘ ’
z ’ ‚ ’
Š ’ `
’ €
’ ’ |’ š †’ ¦ 0100 Œ
¢ ® ¢ ¶ ¢ 8Åm ¤ p
¤
¤ ð
¤ @
@ 2008:07:04 13:02:14 2008:07:04 13:02:14 jR ;ë . ì H P " X œ ¼ Ü ~”HU
ü 4 6 € ü L ƒ “ T • @ v – ¶ — Æ ˜ Æ
Î
ª ê
´ Ð à ô
@ @ N @ T @ Z @ ü z \ ÿ ÿÿ- 7 t ÿÿÿÿ ÿÿ ÿ ÿÿÿÿÿ ‹]d D à à Ÿ "ÿÿà œ ü ÿÿ Canon EOS 400D DIGITAL Firmware 1.1.0 unknown ( �°
N N Õý;]ü ³Õý; ø úþúþþ°ÿÿ
Ÿ p " ˜ð ÿÿÿÿ } EF-S18-55mm f/3.5-5.6 H2162165 €P�
ì Æ" l>
4 c6
_ b4 ƒ ÎÖ ^ ¦ 98£ q ;;å ÿÿ‘ Ž • x€1Ö 1 1 i«¬c È Æ }¹÷ôbó 3 3 ²h ì ê ·Ç r®Ç r®Ó ýgîñ ÏP²
ÏXÓ Bp’uu1
€€a¹ñ ÏP
%uÿ77 û
ÿ77 û
ÿ77 û
ñ ÏZ]þCû”*qþLß'¤þd›l ÜþTXÿ¡p<ÿ´éàcÿÊÁPšÿìŒ\ÛÿTh M ØY }ó¬
ž ·À€Ï 桸
!~ð
Œ¿A` ô% ÿ ÿ _ + % 0 2 # ( J 3 $ ) : 5 2 3 1 7 3 / ( / ) W ; J X e V 9 B B D > > > ' &