diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e5f63a1a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,195 @@ +name: ci + +on: +- pull_request +- push + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + name: + - Node.js 0.10 + - Node.js 0.12 + - io.js 1.x + - io.js 2.x + - io.js 3.x + - Node.js 4.x + - Node.js 6.x + - Node.js 8.x + - 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 + + include: + - name: Node.js 0.10 + node-version: "0.10" + npm-i: mocha@3.5.3 nyc@10.3.2 + + - name: Node.js 0.12 + node-version: "0.12" + npm-i: mocha@3.5.3 nyc@10.3.2 + + - name: io.js 1.x + node-version: "1.8" + npm-i: mocha@3.5.3 nyc@10.3.2 + + - name: io.js 2.x + node-version: "2.5" + npm-i: mocha@3.5.3 nyc@10.3.2 + + - name: io.js 3.x + node-version: "3.3" + npm-i: mocha@3.5.3 nyc@10.3.2 + + - name: Node.js 4.x + node-version: "4.9" + npm-i: mocha@5.2.0 nyc@11.9.0 + + - name: Node.js 6.x + node-version: "6.17" + npm-i: mocha@6.2.2 nyc@14.1.1 + + - name: Node.js 8.x + node-version: "8.17" + npm-i: mocha@7.1.2 nyc@14.1.1 + + - 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" + + - name: Node.js 15.x + node-version: "15.14" + + - 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.1" + + - name: Node.js 22.x + node-version: "22.0" + + - name: Node.js 23.x + node-version: "23" + + - name: Node.js 24.x + node-version: "24" + + steps: + - uses: actions/checkout@v4 + + - 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: Configure npm + run: | + if [[ "$(npm config get package-lock)" == "true" ]]; then + npm config set package-lock false + else + npm config set shrinkwrap false + fi + + - 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@master + if: steps.list_env.outputs.nyc != '' + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: run-${{ matrix.test_number }} + parallel: true + + coverage: + needs: test + runs-on: ubuntu-latest + steps: + - name: Upload code coverage + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..9d1b3041 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,66 @@ +# 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: ["master"] + pull_request: + # The branches below must be a subset of the branches above + branches: ["master"] + 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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7 + 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@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7 + with: + category: "/language:javascript" \ No newline at end of file diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000..66393ed2 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,74 @@ +# 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: [ "master" ] + +# 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + 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@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + 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@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 + with: + sarif_file: results.sarif + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 343dd5a1..00000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -sudo: false -language: node_js -node_js: - - "0.10" - - "0.12" - - "4" - - "6" - - "8" - - "10" diff --git a/README.md b/README.md index 7f5d0807..ea3a8dd5 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,23 @@ -# Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) +# 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 +## Translations This README is also available in other languages: +- [العربية](https://github.com/expressjs/multer/blob/master/doc/README-ar.md) (Arabic) - [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (Spanish) - [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (Chinese) - [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (Korean) - [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (Russian) - [Việt Nam](https://github.com/expressjs/multer/blob/master/doc/README-vi.md) (Vietnam) - [Português](https://github.com/expressjs/multer/blob/master/doc/README-pt-br.md) (Portuguese Brazil) +- [Français](https://github.com/expressjs/multer/blob/master/doc/README-fr.md) (French) +- [O'zbek tili](https://github.com/expressjs/multer/blob/master/doc/README-uz.md) (Uzbek) ## Installation @@ -53,8 +56,8 @@ app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) // req.body will contain the text fields, if there were any }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { +const 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. @@ -78,14 +81,14 @@ app.post('/profile', upload.none(), function (req, res, next) { }) ``` -Here's an example on how multer is used an HTML form. Take special note of the `enctype="multipart/form-data"` and `name="uploaded_file"` fields: +Here's an example on how multer is used in a HTML form. Take special note of the `enctype="multipart/form-data"` and `name="uploaded_file"` fields: ```html
- +
``` @@ -96,9 +99,9 @@ Then in your javascript file you would add these lines to access both the file a const multer = require('multer') const upload = multer({ dest: './public/data/uploads/' }) app.post('/stats', upload.single('uploaded_file'), function (req, res) { - // req.file is the name of your file in the form above, here 'uploaded_file' - // req.body will hold the text fields, if there were any - console.log(req.file, req.body) + // req.file is the name of your file in the form above, here 'uploaded_file' + // req.body will hold the text fields, if there were any + console.log(req.file, req.body) }); ``` @@ -239,7 +242,7 @@ order that the client transmits fields and files to the server. For understanding the calling convention used in the callback (needing to pass null as the first param), refer to -[Node.js error handling](https://www.joyent.com/node-js/production/design/errors) +[Node.js error handling](https://web.archive.org/web/20220417042018/https://www.joyent.com/node-js/production/design/errors) #### `MemoryStorage` @@ -331,3 +334,13 @@ For information on how to build your own storage engine, see [Multer Storage Eng ## License [MIT](LICENSE) + +[ci-image]: https://badgen.net/github/checks/expressjs/multer/master?label=ci +[ci-url]: https://github.com/expressjs/multer/actions/workflows/ci.yml +[test-url]: https://coveralls.io/r/expressjs/multer?branch=master +[test-image]: https://badgen.net/coveralls/c/github/expressjs/multer/master +[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 \ No newline at end of file diff --git a/doc/README-ar.md b/doc/README-ar.md new file mode 100644 index 00000000..8a6d681b --- /dev/null +++ b/doc/README-ar.md @@ -0,0 +1,311 @@ +# Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) + +
+ +تعتبر Multer وسيط node.js لمعالجة `multipart/form-data`, والتي تُستخدم أساسًا لتحميل الملفات. تم بناء هذا الوسيط بالإعتماد على [busboy](https://github.com/mscdex/busboy) لأجل الحصول على أقصى قدر من الكفاءة. + +**ملاحظة**: لن يقوم Multer بمعالجة أي شكل غير متعدد الأجزاء (`multipart/form-data`). + + +## الترجمات + +هذا الملف متاح أيضًا بلغات أخرى: + +- [English](https://github.com/expressjs/multer/blob/master/README.md) (الإنجليزية) +- [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (الإسبانية) +- [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (الصينية) +- [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (الكورية) +- [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (الروسية) +- [Việt Nam](https://github.com/expressjs/multer/blob/master/doc/README-vi.md) (الفتنامية) +- [Português](https://github.com/expressjs/multer/blob/master/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` | الاحتفظ بالمسار الكامل للملفات بدلاً من الاسم الأساسي + +في تطبيق ويب متوسط ​​، قد تكون هناك حاجة فقط إلى `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/master/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/master/StorageEngine.md). + +## الترخيص + +[MIT](LICENSE) diff --git a/doc/README-es.md b/doc/README-es.md index cbb8e74b..f633b7da 100644 --- a/doc/README-es.md +++ b/doc/README-es.md @@ -2,13 +2,13 @@ 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 basado en `multipart/form-data`. +**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: -- [Engilsh](https://github.com/expressjs/multer/blob/master/README.md) (Inglés) +- [English](https://github.com/expressjs/multer/blob/master/README.md) (Inglés) - [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (Chino) - [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (Coreano) - [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (Ruso) @@ -42,28 +42,28 @@ const upload = multer({ dest: 'uploads/' }) const app = express() app.post('/profile', upload.single('avatar'), function (req, res, next) { - // req.file es el `avatar` del archivo - // req.body tendrá los campos textuales, en caso de haber alguno. + // 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 tendrá los campos textuales, en caso de haber alguno. + // req.body contendrá los campos de texto, si los hubiera. }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { +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 tendrá los campos textuales, en caso de haber alguno. + // 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, recomendamos usar el método `.none()`: +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') @@ -76,6 +76,33 @@ app.post('/profile', upload.none(), function (req, res, next) { }) ``` + +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 @@ -84,15 +111,15 @@ Cada archivo contiene la siguiente información: Clave (Key) | Descripción | Nota --- | --- | --- -`fieldname` | Es el nombre del campo especificado en el formulario | +`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 en donde el archivo ha sido guardado | `DiskStorage` +`destination` | La carpeta donde se guardó el archivo | `DiskStorage` `filename` | El nombre del archivo en `destination` | `DiskStorage` -`path` | El camino completo donde se ha subido el archivo (full path) | `DiskStorage` -`buffer` | Un `Buffer` con el archivo completo | `MemoryStorage` +`path` | La ruta completa al archivo subido | `DiskStorage` +`buffer` | Un `Buffer` del archivo completo | `MemoryStorage` ### `multer(opts)` @@ -106,8 +133,8 @@ 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 de subida -`preservePath` | Mantiene la dirección completa de la ubicación de los archivos, en vez de sólo sus nombres +`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 En la aplicación web promedio es probable que sólo se requiera `dest`, siendo configurado como en el siguiente ejemplo: @@ -146,7 +173,7 @@ Acepta sólo campos de texto. En caso de intentar subir un archivo, se generará #### `.any()` -Acepta todos los archivos que han sido enviado. Un arreglo (array) conteniendo los archivos será guardado en `req.files`. +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. @@ -154,7 +181,7 @@ Acepta todos los archivos que han sido enviado. Un arreglo (array) conteniendo l #### `DiskStorage` -El mecanismo de almacenamiento en el disco otorga completo control en la escritura de archivos en tu disco. +El motor de almacenamiento en disco te ofrece un control total sobre el almacenamiento de archivos en tu disco. ```javascript const storage = multer.diskStorage({ @@ -171,21 +198,24 @@ 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` es usado para determinar la capeta en donde los archivos subidos deberían ser almacenados. Esto también puede ser informado mediante un `string` (por ejemplo: `'/tmp/uploads'`). Si ninguna propiedad `destination` es dada, entonces será usado el directorio por defecto en donde el sistema operativo almacena sus archivos temporales. +`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 un `string` es dada a `destination`, Multer se asegurará de que el directorio sea creado en caso de no encontrar uno. +**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, incluyendo también la extensión del archivo. +**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 mecanismo de almacenamiento en memoria almacena los archivos en la memoria en forma de objetos `Buffer`. Para esto no se proveen opciones. +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() @@ -198,7 +228,7 @@ Al usar el almacenamiento en memoria, la información del archivo contendrá un ### `limits` -Un objeto que especifica los límites correpondientes a los tamaños de las siguientes propiedades. 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). +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: @@ -206,7 +236,7 @@ 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 la cantidad de campos | Infinito +`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 @@ -216,7 +246,7 @@ Especificar los límites puede ayudarte a proteger tu sitio contra ataques de de ### `fileFilter` -Asigna ésto a una función que controle cuáles archivos deben ser subidos y cuáles deben ser omitidos. La función debería verse como ésta: +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) { diff --git a/doc/README-fr.md b/doc/README-fr.md new file mode 100644 index 00000000..29417b12 --- /dev/null +++ b/doc/README-fr.md @@ -0,0 +1,331 @@ +# Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) + +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/master/doc/README-ar.md) (Arabe) +- [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (Espagnol) +- [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (Chinois) +- [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (Coréen) +- [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (Russe) +- [Việt Nam](https://github.com/expressjs/multer/blob/master/doc/README-vi.md) (Vietnamien) +- [Português](https://github.com/expressjs/multer/blob/master/doc/README-pt-br.md) (Portugais du Brésil) +- [Français](https://github.com/expressjs/multer/blob/master/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 + +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/master/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/master/StorageEngine.md). + +## License + +[MIT](LICENSE) diff --git a/doc/README-ko.md b/doc/README-ko.md index a58897fa..cc221988 100644 --- a/doc/README-ko.md +++ b/doc/README-ko.md @@ -7,6 +7,8 @@ Multer는 파일 업로드를 위해 사용되는 `multipart/form-data` 를 다 ## 번역 이 문서는 아래의 언어로도 제공됩니다: + +- [العربية](https://github.com/expressjs/multer/blob/master/doc/README-ar.md) (아라비아 말) - [English](https://github.com/expressjs/multer/blob/master/README.md) (영어) - [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (스페인어) - [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (중국어) @@ -42,8 +44,8 @@ app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) // 텍스트 필드가 있는 경우, req.body가 이를 포함할 것입니다. }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { +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에 저장됩니다. // diff --git a/doc/README-pt-br.md b/doc/README-pt-br.md index 5fa2e7ee..f71b64bd 100644 --- a/doc/README-pt-br.md +++ b/doc/README-pt-br.md @@ -1,18 +1,23 @@ # Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) -Multer é um middleware node.js para manipulação `multipart/form-data`, que é usado principalmente para fazer upload de arquivos. Está escrito em cima do [busboy](https://github.com/mscdex/busboy) para máxima eficiência. +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 +## Traduções Este README também está disponível em outros idiomas: -- [English](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (Inglês) +- [English](https://github.com/expressjs/multer/blob/master/README.md) (Inglês) +- [العربية](https://github.com/expressjs/multer/blob/master/doc/README-ar.md) (Árabe) - [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (Espanhol) - [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (Chinês) - [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (Coreano) - [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (Russo) +- [Việt Nam](https://github.com/expressjs/multer/blob/master/doc/README-vi.md) (Vietnã) +- [Português](https://github.com/expressjs/multer/blob/master/doc/README-pt-br.md) (Português Brasil) +- [Français](https://github.com/expressjs/multer/blob/master/doc/README-fr.md) (Francês) +- [O'zbek tili](https://github.com/expressjs/multer/blob/master/doc/README-uz.md) (Uzbequistão) ## Instalação @@ -36,30 +41,30 @@ Não esqueça o `enctype="multipart/form-data"` em seu formulário. ```javascript const express = require('express') -const multer = require('multer') +const multer = require('multer') const upload = multer({ dest: 'uploads/' }) const 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 + // 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 is array of `photos` files - // req.body will contain the text fields, if there were any + // req.files é um array de arquivos `photos` + // req.body conterá os campos de texto, se houver }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { - // req.files is an object (String -> Array) where fieldname is the key, and the value is array of files +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 will contain the text fields, if there were any + // req.body conterá os campos de texto, se houver }) ``` @@ -72,10 +77,34 @@ const multer = require('multer') const upload = multer() app.post('/profile', upload.none(), function (req, res, next) { - // req.body contains the text fields + // 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 @@ -100,7 +129,7 @@ Multer aceita um objeto de opções, a propriedade mais básica é o `dest`, que 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 Multer. +A seguir estão as opções que podem ser passadas para o Multer. Key | Descrição --- | --- @@ -123,7 +152,7 @@ Aceite um único arquivo com o nome `fieldname`. O arquivo único será armazena #### `.array(fieldname[, maxCount])` -Aceite múltiplos arquivos, todos com o nome `fieldname`. Opcional, gera um erro se mais de `maxCount` forem enviados. O array de arquivos serão armazenados em +Aceite múltiplos arquivos, todos com o nome `fieldname`. Opcional, gera um errose forem enviados mais de `maxCount`. O array de arquivos serão armazenados em `req.files`. #### `.fields(fields)` @@ -147,7 +176,7 @@ Aceite apenas campo de texto. Se algum upload de arquivo for feito, um erro com #### `.any()` -Aceita todos os arquivos que são enviaos. Uma matriz de arquivos será armazenada em +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. @@ -187,6 +216,10 @@ Cada função é passada pelo request (`req`) e algumas informações sobre o ar 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. @@ -218,7 +251,7 @@ A especificação dos limites pode ajudar a proteger seu site contra ataques de ### `fileFilter` -Defina isso para uma função para controlar quais arquivos devem ser enviados e quais devem ser ignorados. +Defina isso para uma função para controlar quais arquivos devem ser enviados e quais devem ser ignorados. A função deve ficar assim: @@ -226,7 +259,7 @@ A função deve ficar assim: function fileFilter (req, file, cb) { // A função deve chamar `cb` com um booleano - // to indicate if the file should be accepted + // para indicar se o arquivo deve ser aceito // Para rejeitar este arquivo passe `false`, assim: cb(null, false) @@ -253,12 +286,12 @@ const 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. + // Ocorreu um erro durante o upload. } else if (err) { - // An unknown error occurred when uploading. + // Ocorreu um erro durante o upload. } - // Everything went fine. + // Tudo correu bem. }) }) ``` diff --git a/doc/README-ru.md b/doc/README-ru.md index 5c87faba..d7dd5b64 100644 --- a/doc/README-ru.md +++ b/doc/README-ru.md @@ -4,10 +4,11 @@ Multer — это middleware для фреймворка express для обра **ВАЖНО**: Multer не обрабатывает никакой другой тип форм, кроме `multipart/form-data`. -## Переводы +## Переводы Это README также доступно на других языках: +- [العربية](https://github.com/expressjs/multer/blob/master/doc/README-ar.md) (арабский) - [English](https://github.com/expressjs/multer/blob/master/README.md) (Английский) - [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (Испанский) - [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (Китайский) @@ -51,8 +52,8 @@ app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) // req.body сохранит текстовые поля, если они будут }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { +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 - ключ, и значение - массив файлов // // например: @@ -152,7 +153,7 @@ const upload = multer({ dest: 'uploads/' }) #### `DiskStorage` -Движок дискового пространства. Дает полный контроль над размещением файлов на диск. +Движок дискового пространства. Дает полный контроль над размещением файлов на диск. ```javascript const storage = multer.diskStorage({ @@ -167,13 +168,13 @@ const storage = multer.diskStorage({ const upload = multer({ storage: storage }) ``` -Доступно две опции, расположение `destination` и имя файла `filename`. Обе эти функции определяют, где будет находиться файл после загрузки. +Доступно две опции, расположение `destination` и имя файла `filename`. Обе эти функции определяют, где будет находиться файл после загрузки. `destination` используется, чтобы задать каталог, в котором будут размещены файлы. Может быть задан строкой (например, `'/tmp/uploads'`). Если не задано расположение `destination`, операционная система воспользуется для сохранения каталогом для временных файлов. -**Важно:** Вы должны создать каталог, когда используете `destination`. При передачи в качестве аргумента строки, Multer проверяет, что каталог создан. +**Важно:** Вы должны создать каталог, когда используете `destination`. При передачи в качестве аргумента строки, Multer проверяет, что каталог создан. -`filename` используется, чтобы определить, как будет назван файл внутри каталога. Если +`filename` используется, чтобы определить, как будет назван файл внутри каталога. Если имя файла `filename` не задано, каждому файлу будет сконфигурировано случайное имя без расширения файла. **Важно:** Multer не добавляет никакого файлового расширения, ваша функция должна возвращать имя файла с необходимым расширением. @@ -190,13 +191,13 @@ const upload = multer({ storage: storage }) const storage = multer.memoryStorage() const upload = multer({ storage: storage }) ``` -Когда вы используете этот тип передачи, информация о файле будет содержать поле `buffer`, которое содержит весь файл. +Когда вы используете этот тип передачи, информация о файле будет содержать поле `buffer`, которое содержит весь файл. **ПРЕДУПРЕЖДЕНИЕ**: Загрузка очень больших файлов, или относительно небольших файлов в большом количестве может вызвать переполнение памяти. ### `limits` -Объект, устанавливающий ограничения. Multer прокидывает этот объект напрямую в busboy, поэтому детали можно посмотреть +Объект, устанавливающий ограничения. Multer прокидывает этот объект напрямую в busboy, поэтому детали можно посмотреть [на странице с методами busboy](https://github.com/mscdex/busboy#busboy-methods). Доступны следующие целочисленные значения: @@ -215,7 +216,7 @@ const upload = multer({ storage: storage }) ### `fileFilter` -Задают функцию для того, чтобы решать, какие файлы будут загружены, а какие — нет. Функция может выглядеть так: +Задают функцию для того, чтобы решать, какие файлы будут загружены, а какие — нет. Функция может выглядеть так: ```javascript function fileFilter (req, file, cb) { diff --git a/doc/README-uz.md b/doc/README-uz.md new file mode 100644 index 00000000..f64cc76d --- /dev/null +++ b/doc/README-uz.md @@ -0,0 +1,273 @@ +# Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) + +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/master/doc/README-ar.md) (arabcha) +- [English](https://github.com/expressjs/multer/blob/master/README.md) (inglizcha) +- [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (ispancha) +- [简体中文](https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md) (xitoycha) +- [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (korescha) +- [Português](https://github.com/expressjs/multer/blob/master/doc/README-pt-br.md) (portugalcha) +- [Русский язык](https://github.com/expressjs/multer/blob/master/doc/README-ru.md) (ruscha) +- [Français](https://github.com/expressjs/multer/blob/master/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 + +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/master/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/master/StorageEngine.md). + +## Litsenziya + +[MIT](LICENSE) diff --git a/doc/README-vi.md b/doc/README-vi.md index ac045f23..b5d8bcbd 100644 --- a/doc/README-vi.md +++ b/doc/README-vi.md @@ -54,11 +54,11 @@ app.post('/photos/upload', upload.array('photos', 12), function( // req.body sẽ giữ thông tin gắn kèm (vd: text fields), nếu có }); -var cpUpload = upload.fields([ +var uploadMiddleware = upload.fields([ { name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }, ]); -app.post('/cool-profile', cpUpload, function(req, res, next) { +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: diff --git a/doc/README-zh-cn.md b/doc/README-zh-cn.md index 74bd12d1..66699dda 100644 --- a/doc/README-zh-cn.md +++ b/doc/README-zh-cn.md @@ -10,6 +10,7 @@ Multer 是一个 node.js 中间件,用于处理 `multipart/form-data` 类型 ## 其它语言 +- [العربية](https://github.com/expressjs/multer/blob/master/doc/README-ar.md) (阿拉伯语) - [English](https://github.com/expressjs/multer/blob/master/README.md) (英语) - [Español](https://github.com/expressjs/multer/blob/master/doc/README-es.md) (西班牙文) - [한국어](https://github.com/expressjs/multer/blob/master/doc/README-ko.md) (朝鲜语) @@ -46,8 +47,8 @@ app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) // req.body 将具有文本域数据,如果存在的话 }) -const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }]) -app.post('/cool-profile', cpUpload, function (req, res, next) { +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) 键是文件名,值是文件数组 // // 例如: diff --git a/package.json b/package.json index 6aec9996..fa669581 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "append-field": "^1.0.0", "busboy": "^0.2.11", "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", + "mkdirp": "^0.5.6", "object-assign": "^4.1.1", "on-finished": "^2.3.0", "type-is": "^1.6.4", @@ -33,7 +33,8 @@ "express": "^4.13.1", "form-data": "^1.0.0-rc1", "fs-temp": "^1.1.2", - "mocha": "^3.5.3", + "mocha": "^10.4.0", + "nyc": "^15.1.0", "rimraf": "^2.4.1", "standard": "^14.3.3", "testdata-w3c-json-form": "^1.0.0" @@ -48,6 +49,9 @@ "lib/" ], "scripts": { - "test": "standard && mocha" + "lint": "standard", + "test": "standard && mocha --reporter spec --bail --exit --check-leaks test/", + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/test/express-integration.js b/test/express-integration.js index 87ab8869..0c6acd1c 100644 --- a/test/express-integration.js +++ b/test/express-integration.js @@ -1,6 +1,7 @@ /* eslint-env mocha */ var assert = require('assert') +var http = require('http') var multer = require('../') var util = require('./_util') @@ -106,4 +107,48 @@ describe('Express Integration', function () { 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 multipart data') + 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: port, + path: '/upload', + method: 'POST', + headers: { + 'content-type': 'multipart/form-data; boundary=' + boundary, + 'content-length': body.length + } + } + + var req = http.request(options, function (res) { + assert.strictEqual(res.statusCode, 200) + done() + }) + + req.on('error', function (err) { + done(err) + }) + + req.write(body) + req.end() + }) })