React Js ile birden fazla görseli php kullanarak upload etme
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);
Soru hatalı mı? 👎
Eğer sorunun kurallara aykırı olduğunu düşünüyorsanız lütfen bize bildirin!
Cevaplar (6)
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);
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'));
}
?>
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
Eğer çoklu bir data göndereceksen name ini images[] şeklinde tanımlaman gerekir. Diğer türlü tekil olarak gönderecektir.
inputlara verdiğim name ile tüm görselleri gönderemiyorum maalesef sadece o an seçtiğim görselleri gönderiyor
İ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>