কীভাবে লিমিটেড ধারায় বাইন্ডভ্যালু পদ্ধতি প্রয়োগ করবেন?


117

এখানে আমার কোডের একটি স্ন্যাপশট:

$fetchPictures = $PDO->prepare("SELECT * 
    FROM pictures 
    WHERE album = :albumId 
    ORDER BY id ASC 
    LIMIT :skip, :max");

$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);

if(isset($_GET['skip'])) {
    $fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);    
} else {
    $fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);  
}

$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);

আমি পাই

আপনার এসকিউএল সিনট্যাক্সে আপনার একটি ত্রুটি রয়েছে; ম্যানুয়ালটি পরীক্ষা করুন যা আপনার মাইএসকিউএল সার্ভার সংস্করণের সাথে সামঞ্জস্য করে ডান সিনট্যাক্সের জন্য '' 15 ', 15' এর নিকটবর্তী লাইনে 1 ব্যবহার করতে

দেখে মনে হচ্ছে পিডিও এসকিউএল কোডের লিমিটেড অংশে আমার ভেরিয়েবলগুলিতে একক উদ্ধৃতি যুক্ত করছে। আমি এটি সন্ধান করলাম আমি এই বাগটি পেয়েছি যা আমি মনে করি এটি সম্পর্কিত: http://bugs.php.net/bug.php?id=44639

এটাই কি আমি তাকিয়ে আছি? এই বাগ 2008 এপ্রিল থেকে খোলা হয়েছে! এর মধ্যে আমাদের কী করার কথা?

আমার কিছু পৃষ্ঠাগুলি তৈরি করতে হবে এবং এসকিউএল স্টেটমেন্ট প্রেরণের আগে ডেটা পরিষ্কার, বর্গফুট ইনজেকশন-নিরাপদ নিশ্চিত করা দরকার।



উত্তর:


165

আমার মনে আছে এই সমস্যাটি আগে ছিল। বিন্যাস ফাংশনে পাস করার আগে একটি পূর্ণসংখ্যার মানটি কাস্ট করুন। আমি মনে করি এটি এটি সমাধান করে।

$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);

37
ধন্যবাদ! কিন্তু পিএইচপি 5.3-তে, উপরোক্ত কোডটি "মারাত্মক ত্রুটি: রেফারেন্স দ্বারা প্যারামিটার 2 পাস করতে পারে না" বলে ত্রুটি ছুঁড়েছে। এটি সেখানে একটি int কাস্টিং পছন্দ করে না। পরিবর্তে (int) trim($_GET['skip']), চেষ্টা করুন intval(trim($_GET['skip']))
মার্টিন

5
ডিজাইন / সুরক্ষা (বা অন্য) দৃষ্টিকোণ থেকে কেউ যদি কেন এমন হয় তার ব্যাখ্যা সরবরাহ করে তবে শীতল হবে।
রস

6
এটি কেবল তখনই কাজ করবে যদি এমুলেটেড প্রস্তুত বিবৃতি সক্ষম হয় । এটি অক্ষম হলে এটি ব্যর্থ হবে (এবং এটি অক্ষম করা উচিত!)
মাদারার ঘোস্ট

4
@Ross আমি বিশেষভাবে এর উত্তর দিতে পারি না - তবে আমি উল্লেখ করতে পারি যে এই সমস্ত পিএইচপি / এমওয়াইএসকিউএল / পিডিও উন্মাদনার পরে লিমিটেড এবং অফসেট এমন বৈশিষ্ট্যগুলি ছিল যেগুলি সার্কিটকে আঘাত করেছিল ... আসলে, আমি বিশ্বাস করি যে লর্ডডরফ নিজেই তদারকি করেছিলেন believe কয়েক বছর আগে সীমাবদ্ধ বাস্তবায়ন। না, এটি প্রশ্নের উত্তর দেয় না, তবে এটি ইঙ্গিত দেয় যে এটি একটি
আফটার মার্কেট

2
@ রোস পিডিও মানগুলির পরিবর্তে ভেরিয়েবলের সাথে বাঁধার অনুমতি দেয় না। আপনি যদি বাইন্ডারাম চেষ্টা করেন (': কিছু', 2) আপনার একটি ত্রুটি হবে কারণ পিডিও কোনও ভেরিয়েবলের জন্য একটি পয়েন্টার ব্যবহার করে যা কোনও সংখ্যা থাকতে পারে না (যদি $ আমি 2 হয় তবে আপনি towards i এর দিকে পয়েন্টার রাখতে পারেন তবে দিকে না ২ নম্বর).
ক্রিস্তিজান

44

সবচেয়ে সহজ সমাধানটি হবে এমুলেশন মোডটি বন্ধ করে দেওয়া। আপনি কেবল নিম্নলিখিত লাইনটি যুক্ত করে এটি করতে পারেন

$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

এছাড়াও, PDO সংযোগ তৈরি করার সময় এই মোডটি কনস্ট্রাক্টর প্যারামিটার হিসাবে সেট করা যেতে পারে । এটি আরও ভাল সমাধান হতে পারে যেহেতু তাদের রিপোর্টকারীরা setAttribute()ফাংশন সমর্থন করে না বলে কিছু রিপোর্ট করেছে ।

এটি কেবল আপনার বাঁধাইয়ের সাথে সমস্যার সমাধান করবে না, তবে আপনাকে সরাসরি মানগুলিতে প্রেরণ execute()করতে দেবে যা আপনার কোডকে নাটকীয়ভাবে খাটো করে তুলবে। এমুলেশন মোডটি ইতিমধ্যে সেট হয়ে গেছে ধরে নেওয়া, পুরো ব্যাপারটি কোডের অর্ধ ডজন লাইনেরও বেশি সময় নেবে

$skip = isset($_GET['skip']) ? (int)trim($_GET['skip']) : 0;
$sql  = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$stmt  = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);

SQLSTATE[IM001]: Driver does not support this function: This driver doesn't support setting attributes... কেন এটি আমার পক্ষে এত সহজ নয় :) যদিও আমি নিশ্চিত যে এটি সেখানে বেশিরভাগ লোককে পাবে, আমার ক্ষেত্রে আমি গ্রহণযোগ্য উত্তরের অনুরূপ কিছু ব্যবহার করে শেষ করেছি। ভবিষ্যতের পাঠকদের কাছে কেবল একটি শীর্ষস্থানীয়!
ম্যাথু জনসন

@ ম্যাথহে জনসন এটি ড্রাইভার কী?
আপনার কমন সেন্স

আমি নিশ্চিত নই, তবে ম্যানুয়ালটিতে এটি বলেছে PDO::ATTR_EMULATE_PREPARES Enables or disables emulation of prepared statements. Some drivers do not support native prepared statements or have limited support for them। এটি আমার কাছে নতুন, তবে আবার আমি কেবল পিডিও দিয়ে শুরু করছি। সাধারণত mysqli ব্যবহার করুন, তবে অনুভূত যে আমি আমার দিগন্তগুলি আরও প্রশস্ত করার চেষ্টা করব।
ম্যাথু জনসন

@ ম্যাথহে জনসন যদি আপনি মাইএসকিএল-এর জন্য পিডিও ব্যবহার করেন তবে ড্রাইভার এই ফাংশনটি পুরোপুরি সমর্থন করে। সুতরাং, আপনি কোনও ভুলের কারণে এই বার্তাটি পেয়ে
আপনার সাধারণ সংবেদন

1
আপনি যদি ড্রাইভার সমর্থন সমস্যার বার্তা পেয়ে থাকেন তবে আপনি setAttributeপিডিও অবজেক্টের জন্য না হয়ে স্টেটমেন্টটি ($ stm, $ stmt) কল করেছেন কিনা তা আবার পরীক্ষা করে দেখুন ।
ইয়াহং আহন

17

বাগের প্রতিবেদনটি দেখে, নিম্নলিখিতগুলি কার্যকর হতে পারে:

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);  

তবে আপনি কি নিশ্চিত যে আপনার আগত ডেটা সঠিক? কারণ ত্রুটি বার্তায়, সংখ্যাটির পরে কেবল একটি উদ্ধৃতি বলে মনে হচ্ছে (পুরো সংখ্যাটি উদ্ধৃতিতে আবদ্ধ হওয়ার বিপরীতে)। এটি আপনার আগত ডেটাগুলির সাথে একটি ত্রুটিও হতে পারে। আপনি কি print_r($_GET);এটি করতে একটি করতে পারেন?


1
'' 15 ', 15'। প্রথম সংখ্যাটি উদ্ধৃতিতে সম্পূর্ণরূপে সংযুক্ত। দ্বিতীয় সংখ্যাটির কোনও উদ্ধৃতি নেই। হ্যাঁ, তথ্য ভাল।
নাথান এইচ

8

এটি ঠিক যেমন সংক্ষিপ্তসার।
সীমাবদ্ধ / অফফেসেট মানগুলিকে প্যারামিটারাইজ করার জন্য চারটি বিকল্প রয়েছে:

  1. উপরেPDO::ATTR_EMULATE_PREPARES বর্ণিত হিসাবে অক্ষম করুন ।

    যা ->execute([...])সর্বদা স্ট্রিং হিসাবে প্রদর্শিত হতে প্রদত্ত মানগুলিকে প্রতিরোধ করে।

  2. ম্যানুয়াল ->bindValue(..., ..., PDO::PARAM_INT)প্যারামিটার জনসংখ্যায় স্যুইচ করুন ।

    যা তবে কোনও -> সম্পাদনকারী তালিকার চেয়ে কম সুবিধাজনক []।

  3. এসকিউএল কোয়েরি প্রস্তুত করার সময় কেবল এখানে একটি ব্যতিক্রম করুন এবং কেবল প্লেইন পূর্ণসংখ্যাকে বিভক্ত করুন।

     $limit = intval($limit);
     $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");

    Ingালাই গুরুত্বপূর্ণ। আপনি সাধারণত এই ->prepare(sprintf("SELECT ... LIMIT %d", $num))জাতীয় উদ্দেশ্যে ব্যবহার দেখতে পাবেন ।

  4. যদি আপনি মাইএসকিউএল ব্যবহার না করে থাকেন তবে উদাহরণস্বরূপ এসকিউএলাইট বা পোস্টগ্রিস; আপনি সরাসরি এসকিউএল এ আবদ্ধ পরামিতি কাস্ট করতে পারেন।

     SELECT * FROM tbl LIMIT (1 * :limit)

    আবার, মাইএসকিউএল / মারিয়াডিবি লিমিটেড ধারায় এক্সপ্রেশন সমর্থন করে না। এখনো না.


1
আমি স্প্রিন্টফ () 3% এর সাথে% d ব্যবহার করতাম, আমি বলব এটি ভেরিয়েবলের সাথে কিছুটা স্থিতিশীল।
hakre

হ্যাঁ, বৈকল্পিক castালাই + ইন্টারপোলেশন সবচেয়ে ব্যবহারিক উদাহরণ নয়। আমি প্রায়ই এই {$_GET->int["limit"]}ধরনের ক্ষেত্রে আমার অলস ব্যবহার করতাম ।
মারিও

7

জন্য LIMIT :init, :end

আপনাকে সেভাবে বাঁধতে হবে। যদি $req->execute(Array());এটির মতো এমন কিছু কাজ করে যা এটি PDO::PARAM_STRঅ্যারেতে সমস্ত ভার্সে ফেলে দেয় এবং আপনার জন্য LIMITএকেবারে পূর্ণসংখ্যার প্রয়োজন হয় need আপনার ইচ্ছামতো বিন্দুভ্যালু বা বিন্ডপারাম।

$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);

2

যেহেতু কেউ কেন ঘটছে তা ব্যাখ্যা করেনি, তাই আমি একটি উত্তর যুক্ত করছি। এটি এর ব্যবহারের কারণ হ'ল আপনি ব্যবহার করছেন trim()। আপনি যদি পিএইচপি ম্যানুয়ালটির জন্য তাকান trimতবে রিটার্নের ধরণটি string। আপনি তখন এটি পাস করার চেষ্টা করছেন PDO::PARAM_INT। এটিকে ঘুরে দেখার কয়েকটি উপায়:

  1. filter_var($integer, FILTER_VALIDATE_NUMBER_INT)আপনি কোনও পূর্ণসংখ্যা পেরিয়ে যাচ্ছেন তা নিশ্চিত করতে ব্যবহার করুন ।
  2. যেমন অন্যরা বলেছেন, ব্যবহার করছেন intval()
  3. সাথে কাস্টিং (int)
  4. এটি দিয়ে পূর্ণসংখ্যা কিনা তা পরীক্ষা করা হচ্ছে is_int()

আরও প্রচুর উপায় রয়েছে তবে মূলত এটিই মূল কারণ।


3
পরিবর্তনশীল সর্বদা একটি পূর্ণসংখ্যার হয়ে থাকলেও এটি ঘটে।
felwithe

1

bindValue অফসেট এবং PDO :: PARAM_INT ব্যবহার করে সীমাবদ্ধ করে এটি কাজ করবে


-1

// আগে (বর্তমান ত্রুটি) $ ক্যোয়ারী = ".... লিমিট: পি 1, 30;"; ... m stmt-> bindParam (': p1', $ limiteInferior);

// আফটার (ত্রুটি সংশোধন) $ ক্যোয়ারী = ".... লিমিট: পি 1, 30;"; ... $ limiteInferior = (int) $ limiteInferior; $ stmt-> bindParam (': p1', $ সীমাবদ্ধতা, PDO :: PARAM_INT);


-1

PDO::ATTR_EMULATE_PREPARES আমাকে দিয়েছে

ড্রাইভার এই ফাংশনটিকে সমর্থন করে না: এই ড্রাইভারটি বৈশিষ্ট্যগুলির ত্রুটিটি সেট করার পক্ষে সমর্থন করে না।

আমার কাজের দিকটি $limitএকটি স্ট্রিং হিসাবে একটি ভেরিয়েবল সেট করা ছিল , তারপরে এটি নিম্নলিখিত বিবরণ হিসাবে প্রস্তুত বিবৃতিতে একত্রিত করুন:

$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
    $stmt->execute( array( ':cid' => $company_id ) );
    ...
}
catch ( Exception $e ) {
    ...
}

-1

পিএইচপি-র বিভিন্ন সংস্করণ এবং পিডিওর বৈচিত্র্যের মধ্যে প্রচুর চলছে। আমি এখানে 3 বা 4 টি পদ্ধতি চেষ্টা করেছি কিন্তু LIMIT কাজ করতে পারিনি।
আমার পরামর্শটি হল একটি অবতরণ () ফিল্টার সহ স্ট্রিং ফর্ম্যাটিং / কনকিটেশনেশন :

$sql = 'SELECT * FROM `table` LIMIT ' . intval($limitstart) . ' , ' . intval($num).';';

এসকিউএল ইঞ্জেকশন প্রতিরোধের জন্য ইনটওয়াল () ব্যবহার করা খুব গুরুত্বপূর্ণ, বিশেষত যদি আপনি limit _GET বা এর মতো আপনার সীমাটি পেয়ে থাকেন। আপনি যদি এটি করেন তবে এটি সীমাবদ্ধতার কাজ করার সহজতম উপায়।

'পিডিও-তে লিমিটেডের সমস্যা' নিয়ে প্রচুর আলোচনা আছে তবে আমার এখানে মনে হয়েছে যে পিডিও প্যারামগুলি কখনই লিমিটেডের জন্য ব্যবহার করা উচিত নয় কারণ তারা সবসময়ই একটি দ্রুত ফিল্টার কাজ করবে। তবুও, এটি কিছুটা বিভ্রান্তিকর কারণ দর্শন সবসময়ই কোনও এসকিউএল ইঞ্জেকশন নিজেকে ফিল্টার না করে বরং 'পিডিও হ্যান্ডেল করে রাখে' been

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.