v2.5.2
Giriş yap

React Js ile birden fazla görseli php kullanarak upload etme

singlestroke
299 defa görüntülendi

Sorunu üçüncü kez yazışım macbook'da ki çift parmak ile önce ki
sayfaya gitme özelliği yüzünden üçüncü kez yazıyorum sorunu
sorunum şu bir form ile 3 tane görsel seçiyorum bu görselleri php
ile yazdığım back-end servisine yollayıp kaydedicem
resimler [file Object] olarak gidiyor servisime ben bunu back-end
tarafında nasıl karşılamam gerek ? yahut form sayfamda yanlış olan bir şey var mı ?

Kodlarıma da kalite açısından bi göz gezdirirseniz çok mutlu olurum eleştirilerinize açığım :D

import React, { useEffect, useState } from "react";
import { ProductServices, CategoryServices } from "../services";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

import Header from "./components/header.js";
import Footer from "./components/footer";
import Sidebar from "./components/sidebar.js";
import Menu from "./components/menu";
import { success, warning } from "../functions";

function ProductCreate() {
  const [images, setImages] = useState([]);

  const submitHandle = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("code", "Deneme123");
    formData.append("category", 2);
    formData.append("explanation", "Açıklama yazısı");
    formData.append("image", images);

    ProductServices.productCreate(formData).then((res) =>
      res.result === true ? success(res.message) : warning(res.message)
    );
  };

  const onChangeImage = (e) => {
    e.preventDefault();
    if (e.target.files[0] != null) {
      const allimages = Array.from(images);

      images.length >= 3
        ? warning("Daha Fazla Görsel Seçemezsin")
        : Array.from(e.target.files).forEach((element) => {
            allimages.push(element);
          });
      setImages(allimages);
    }
  };

  function deleteImage(e, index) {
    e.preventDefault();
    const allimages = Array.from(images);
    allimages.splice(index, 1);
    setImages(allimages);
  }

  function imageToCover(e, cover, index) {
    e.preventDefault();

    const allimages = Array.from(images);
    allimages.unshift(cover);

    allimages.splice(index + 1, 1);
    setImages(allimages);
  }

  return (
    <div>
      <Sidebar />
      <Header />
      <div className="max-w-7xl mx-auto grid grid-cols-12 gap-4 mt-20 md:mt-24 px-4 xl:px-0">
        <Menu />
        <div className="col-span-12 lg:col-span-9">
          <div className="mt-5 md:col-span-2 md:mt-0">
            <div className="mb-4">
              <h5>Ürün Oluştur</h5>
              <p className="text-xs">
                Kategorilere özel ürünler ekleyerek ürünlerinizi sunabilirsiniz.
              </p>
            </div>
            <form>
              <div className="shadow sm:overflow-hidden sm:rounded-md">
                <div className="space-y-6 bg-white px-4 py-5 sm:p-6">
                  <div>
                    <div className="col-span-3 sm:col-span-2">
                      <label
                        htmlFor="code"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Ürün Kodu
                      </label>
                      <div className="mt-1 flex rounded-md shadow-sm">
                        <span className="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-3 text-sm text-gray-500">
                          #
                        </span>
                        <input
                          type="text"
                          name="code"
                          id="code"
                          className="block p-4 border w-full flex-1 rounded-none rounded-r-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
                          placeholder="Ürün kodu girin"
                        />
                      </div>
                    </div>
                  </div>
                  <div>
                    <label
                      htmlFor="about"
                      className="block text-sm font-medium text-gray-700"
                    >
                      Açıklaması
                    </label>
                    <div className="mt-1">
                      <textarea
                        id="about"
                        name="about"
                        rows={3}
                        className="mt-1 p-4 border block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
                        placeholder="Ürünün deyaylı açıklamasını girin"
                        defaultValue={""}
                      />
                    </div>
                    <p className="mt-2 text-sm text-gray-500">
                      Ürün hakkında yazdığınız açıklama ürün sayfasında yer
                      alacaktır bu açıklama ne kadar uzun olursa o kadar faydalı
                      olacaktır.
                    </p>
                  </div>
                  <div>
                    <label className="block text-sm font-medium text-gray-700">
                      Ürün görselleri
                    </label>
                    <div className="mt-1 mb-6 flex justify-center rounded-md border-2 border-dashed border-gray-300 px-6 pt-5 pb-6">
                      <div className="space-y-1 text-center">
                        <svg
                          className="mx-auto h-12 w-12 text-gray-400"
                          stroke="currentColor"
                          fill="none"
                          viewBox="0 0 48 48"
                          aria-hidden="true"
                        >
                          <path
                            d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
                            strokeWidth={2}
                            strokeLinecap="round"
                            strokeLinejoin="round"
                          />
                        </svg>
                        <div className="text-sm text-gray-600">
                          <label
                            htmlFor="file-upload"
                            className="relative cursor-pointer rounded-md bg-white font-medium text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-500 focus-within:ring-offset-2 hover:text-indigo-500"
                          >
                            <span>Resim Seç</span>
                            <input
                              id="file-upload"
                              name="file-upload"
                              type="file"
                              accept="image/*"
                              className="sr-only"
                              multiple
                              onChange={(e) => onChangeImage(e)}
                            />
                          </label>
                        </div>
                        <p className="text-xs text-gray-500">
                          Sadece Görsel Seçebilirsiniz
                        </p>
                      </div>
                    </div>
                  </div>

                  <div className="bg-gray-100 p-4 rounded grid grid-cols-2 md:grid-cols-3 gap-3">
                    {images && images.length === 0 && (
                      <div className="">Henüz Görsel Eklenmedi</div>
                    )}
                    {images &&
                      images.map((cover, index) => (
                        <div
                          key={index}
                          className="min-h-80 relative bg-gray-200 group-hover:opacity-75 lg:aspect-none lg:h-80"
                        >
                          {index === 0 ? (
                            <div className="h-full">
                              <img
                                src={URL.createObjectURL(cover)}
                                alt={index}
                                className="ring-2 ring-red-400 rounded h-full w-full object-cover object-center lg:h-full lg:w-full"
                              />
                              <div className="absolute bottom-0 left-0 right-0 p-2 sm:p-4">
                                <div className="w-full inline-flex rounded-md shadow-sm">
                                  <button
                                    onClick={(e) => deleteImage(e, index)}
                                    type="button"
                                    className="py-2 text-red-700 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white text-gray-700 align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-all text-sm dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Sil
                                  </button>
                                </div>
                              </div>
                            </div>
                          ) : (
                            <div className="h-full">
                              <img
                                src={URL.createObjectURL(cover)}
                                alt={index}
                                className="ring-2 ring-white rounded h-full w-full object-cover object-center lg:h-full lg:w-full"
                              />
                              <div className="absolute bottom-0 left-0 right-0 p-2 sm:p-4">
                                <div className="w-full inline-flex rounded-md shadow-sm">
                                  <button
                                    onClick={(e) => deleteImage(e, index)}
                                    type="button"
                                    className="py-2 text-red-700 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white text-gray-700 align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-all text-sm dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Sil
                                  </button>

                                  <button
                                    onClick={(e) =>
                                      imageToCover(e, cover, index)
                                    }
                                    type="button"
                                    className="py-2 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white text-gray-700 align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-all text-sm dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Kapak
                                  </button>
                                </div>
                              </div>
                            </div>
                          )}
                        </div>
                      ))}
                  </div>
                </div>

                <div className="bg-gray-50 px-4 py-3 text-right sm:px-6">
                  <button
                    onClick={(e) => submitHandle(e)}
                    type="submit"
                    className="inline-flex justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
                  >
                    Oluştur
                  </button>
                </div>
              </div>
            </form>
          </div>
          <Footer />
        </div>
      </div>
      <ToastContainer />
    </div>
  );
}

export default ProductCreate;

Request.js

function request(url, data = false, method = "GET") {
  return new Promise(async (resolve, reject) => {
    const options = {
      method,
    };

    if (data && method === "POST") {
      options.body = data;
    }

    const response = await fetch(url, options);
    if (response.ok) {
      resolve(response.json());
    } else {
      reject(response.json());
    }
  });
}

export const post = (url, data) => request(url, data, "POST");
export const get = (url) => request(url);

Cevap yaz
Cevaplar (6)
devepdogukan
639 gün önce

Anladım kendi verilerinide FormData'ya ekleyebilirsin. İlla name ile oluşturmana gerek yok önemli olan backend'den nasıl karşıladığın

formData.append("image[]", images);
singlestroke
639 gün önce

Projeyi çalıştırdım arkadaşlar en azından bu aşamayı hallettim kodlar aşağıda;

back-end tarafı henüz bitmiş halde değil fakat şimdilik işimi görüyor dosyaların tiplerini vs sorgulamadım farkındayım

    import React, { useEffect, useState } from "react";
import { ProductServices, CategoryServices } from "../services";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

import Header from "./components/header.js";
import Footer from "./components/footer";
import Sidebar from "./components/sidebar.js";
import Menu from "./components/menu";
import { success, warning } from "../functions";

function ProductCreate() {
  const [images, setImages] = useState([]);
  const [code, setCode] = useState();
  const [category, setCategory] = useState();
  const [explanation, setExplanation] = useState();
  const [categories, setCategories] = useState();

  useEffect(() => {
    CategoryServices.allCategory().then((all) => setCategories(all));
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = new FormData();
    formData.append("code", code);
    formData.append("category", category);
    formData.append("explanation", explanation);
    images.forEach((element) => {
      formData.append("image[]", element);
    });

    ProductServices.productCreate(formData).then((res) =>
      console.log(res.result)
    );
  };

  const onChangeImage = (e) => {
    e.preventDefault();
    if (e.target.files[0] != null) {
      const allimages = Array.from(images);

      images.length >= 3
        ? warning("Daha Fazla Görsel Seçemezsin")
        : Array.from(e.target.files).forEach((element) => {
            allimages.push(element);
          });
      setImages(allimages);
    }
  };

  function deleteImage(e, index) {
    e.preventDefault();
    const allimages = Array.from(images);
    allimages.splice(index, 1);
    setImages(allimages);
  }

  function imageToCover(e, cover, index) {
    e.preventDefault();

    const allimages = Array.from(images);
    allimages.unshift(cover);

    allimages.splice(index + 1, 1);
    setImages(allimages);
  }

  return (
    <div>
      <Sidebar />
      <Header />
      <div className="max-w-7xl mx-auto grid grid-cols-12 gap-4 mt-16 md:mt-24 px-4 xl:px-0">
        <Menu />
        <div className="col-span-12 lg:col-span-9">
          <div className="mt-5 md:col-span-2 md:mt-0">
            <div className="mb-4">
              <h5>Ürün Oluştur</h5>
              <p className="text-xs">
                Kategorilere özel ürünler ekleyerek ürünlerinizi sunabilirsiniz.
              </p>
            </div>
            <form
              onSubmit={(e) => handleSubmit(e)}
              encType="multipart/form-data"
            >
              <div className="shadow sm:overflow-hidden sm:rounded-md">
                <div className="space-y-6 bg-white px-4 py-5 sm:p-6">
                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 lg:gap-6">
                    <div>
                      <div className="col-span-3 sm:col-span-2">
                        <label
                          htmlFor="code"
                          className="block text-sm font-medium text-gray-700"
                        >
                          Ürün Kodu
                        </label>
                        <div className="mt-1 flex rounded-md shadow-sm">
                          <span className="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-2.5 text-sm text-gray-500">
                            #
                          </span>
                          <input
                            onChange={(e) => setCode(e.target.value)}
                            type="text"
                            name="code"
                            id="code"
                            className="block p-4 border w-full flex-1 rounded-none rounded-r-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
                            placeholder="Ürün kodu girin"
                          />
                        </div>
                      </div>
                    </div>
                    <div>
                      <div className="col-span-3 sm:col-span-2">
                        <label
                          htmlFor="category"
                          className="block text-sm font-medium text-gray-700"
                        >
                          Kategori Seç
                        </label>
                        <div className="mt-1 flex rounded-md shadow-sm">
                          <select
                            onChange={(e) => setCategory(e.target.value)}
                            name="category"
                            id="category"
                            className="block p-4 border w-full flex-1 rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
                          >
                            <option defaultValue>Kategori Seç</option>
                            {categories &&
                              categories.map((category) => (
                                <option key={category.id} value={category.id}>
                                  {category.title}
                                </option>
                              ))}
                          </select>
                        </div>
                      </div>
                    </div>
                  </div>
                  <div>
                    <label
                      htmlFor="about"
                      className="block text-sm font-medium text-gray-700"
                    >
                      Açıklaması
                    </label>
                    <div className="mt-1">
                      <textarea
                        onChange={(e) => setExplanation(e.target.value)}
                        id="explanation"
                        name="explanation"
                        rows={3}
                        className="mt-1 p-4 border block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
                        placeholder="Ürünün detaylı açıklamasını girin"
                        defaultValue={""}
                      />
                    </div>
                    <p className="mt-2 text-sm text-gray-500">
                      Ürün hakkında yazdığınız açıklama ürün sayfasında yer
                      alacaktır bu açıklama ne kadar uzun olursa o kadar faydalı
                      olacaktır.
                    </p>
                  </div>
                  <div>
                    <label className="block text-sm font-medium text-gray-700">
                      Ürün Görselleri
                    </label>
                    <div className="mt-1 mb-6 flex justify-center rounded-md border-2 border-dashed border-gray-300 px-6 pt-5 pb-6">
                      <div className="space-y-1 text-center">
                        <svg
                          className="mx-auto h-12 w-12 text-gray-400"
                          stroke="currentColor"
                          fill="none"
                          viewBox="0 0 48 48"
                          aria-hidden="true"
                        >
                          <path
                            d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
                            strokeWidth={2}
                            strokeLinecap="round"
                            strokeLinejoin="round"
                          />
                        </svg>
                        <div className="text-sm text-gray-600">
                          <label
                            htmlFor="image"
                            className="relative cursor-pointer rounded-md bg-white font-medium text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-500 focus-within:ring-offset-2 hover:text-indigo-500"
                          >
                            <span>Resim Seç</span>
                            <input
                              id="image"
                              name="image"
                              type="file"
                              accept="image/*"
                              className="sr-only"
                              multiple="multiple"
                              onChange={(e) => onChangeImage(e)}
                            />
                          </label>
                        </div>
                        <p className="text-xs text-gray-500">
                          Ürün fotoğrafları seçin
                        </p>
                      </div>
                    </div>
                  </div>

                  <div className="bg-gray-100 p-4 rounded grid grid-cols-2 md:grid-cols-3 gap-3">
                    {images && images.length === 0 && (
                      <div className="">Henüz Görsel Eklenmedi</div>
                    )}
                    {images &&
                      images.map((cover, index) => (
                        <div
                          key={index}
                          className="min-h-80 relative bg-gray-200 group-hover:opacity-75 lg:aspect-none lg:h-80"
                        >
                          {index === 0 ? (
                            <div className="h-full">
                              <img
                                src={URL.createObjectURL(cover)}
                                alt={index}
                                className="ring-2 ring-red-400 rounded h-full w-full object-cover object-center lg:h-full lg:w-full"
                              />
                              <div className="absolute bottom-0 left-0 right-0 p-2 sm:p-4">
                                <div className="w-full inline-flex rounded-md shadow-sm">
                                  <button
                                    onClick={(e) => deleteImage(e, index)}
                                    type="button"
                                    className="py-2 text-red-700 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-al dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Sil
                                  </button>
                                </div>
                              </div>
                            </div>
                          ) : (
                            <div className="h-full">
                              <img
                                src={URL.createObjectURL(cover)}
                                alt={index}
                                className="ring-2 ring-white rounded h-full w-full object-cover object-center lg:h-full lg:w-full"
                              />
                              <div className="absolute bottom-0 left-0 right-0 p-2 sm:p-4">
                                <div className="w-full inline-flex rounded-md shadow-sm">
                                  <button
                                    onClick={(e) => deleteImage(e, index)}
                                    type="button"
                                    className="py-2 text-red-700 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white  align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-all  dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Sil
                                  </button>

                                  <button
                                    onClick={(e) =>
                                      imageToCover(e, cover, index)
                                    }
                                    type="button"
                                    className="py-2 text-xs w-full inline-flex justify-center items-center gap-2 -ml-px first:rounded-l-lg first:ml-0 last:rounded-r-lg border font-medium bg-white text-gray-700 align-middle hover:bg-gray-50 focus:z-10 focus:outline-none focus:ring-2 focus:ring-blue-600 transition-all  dark:bg-gray-800 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400"
                                  >
                                    Kapak
                                  </button>
                                </div>
                              </div>
                            </div>
                          )}
                        </div>
                      ))}
                  </div>
                </div>

                <div className="bg-gray-200 px-4 py-3 text-right sm:px-6">
                  <button
                    type="submit"
                    className="inline-flex justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
                  >
                    OLUŞTUR
                  </button>
                </div>
              </div>
            </form>
          </div>
          <Footer />
        </div>
      </div>
      <ToastContainer />
    </div>
  );
}

export default ProductCreate;

Backend tarafı;

    <?php
include 'services/productServices.php';
header('Access-Control-Allow-Origin: *');
header('Access-Control-Headers: X-Requested-Witch');
header('Access-Control-Headers: Content-Type');

$code = $_POST['code'];
$category = $_POST['category'];
$explanation = $_POST['explanation'];

$createProduct = $productServices->createProduct($code, $category, $explanation);

if($createProduct['result']){

    $result = false;

    foreach($_FILES["image"]["tmp_name"] as $key=>$tmp_name) {
        $filename=$_FILES["image"]["name"][$key];
        $tempname=$_FILES["image"]["tmp_name"][$key];
        $ext = pathinfo($filename,PATHINFO_EXTENSION);
        $target_dir = "images/";
        $target_file = $code ."-". rand(1, 1000) .".". $ext;
    
        if (move_uploaded_file($tempname, $target_dir .$target_file)) {
            if($productServices->createImages($createProduct['id'], $target_file)){
                $result = true;
            }else{
                $result = false;
            }
        } else {
            $result = false;
        }
    }

    if($result == true){
        echo json_encode(array('result'=>true,'message'=>'Ürün eklendi'));
    }else{
        echo json_encode(array('result'=>false,'message'=>'Ürün veritabanı eklenirken hata oldu'));
    }

}else {
    echo json_encode(array('result'=>false,'message'=>'Ürün veritabanı eklenirken hata oldu'));
}

?>


singlestroke
639 gün önce

Tamam ama sorun şu ben görselleri seçtikten sonra mesela ben arasından bir tanesini sildim
ee şimdi ben e.target ile bunu upload ettiğimde o sildiğim fotoğrafı baz almıyor çünkü ben seçilen görselleri
bir diziye koyuyorum ve o dizi üzerinden silme yahut yer değiştirme (kapak fotoğrafı için) gibi işlemler yapıyorum bu işlemler
upload ettiğimde geçerli olmuyor çünkü benim oluşturduğum diziyi değil input üzerinde ki diziyi aktarıyor benim amacım
kendi oluşturduğum diziyi upload etmek

devepdogukan
639 gün önce

Eğer çoklu bir data göndereceksen name ini images[] şeklinde tanımlaman gerekir. Diğer türlü tekil olarak gönderecektir.

singlestroke
639 gün önce

inputlara verdiğim name ile tüm görselleri gönderemiyorum maalesef sadece o an seçtiğim görselleri gönderiyor

devepdogukan
639 gün önce

İlk olarak formun içindeki dataları onSubmit ile dinlemen gerekiyor.Inputlarına name vererek FormData ile kolaylıkla yakalayabilirsin.

const handleSubmit = (e) => {
    const data = new FormData(e.target);
    formData.append("image", images);
    request.post('url',data)
}

<form onSubmit={handleSubmit}>
    <input name="deneme" type="file" />
</form>