วิธีป้องกันการส่งฟอร์มซ้ำเมื่อรีเฟรชหน้าเว็บ (F5 / CTRL + R)


132

ฉันมีรูปแบบง่าย ๆ ที่ส่งข้อความไปยังตาราง SQL ของฉัน ปัญหาคือหลังจากที่ผู้ใช้ส่งข้อความพวกเขาสามารถรีเฟรชหน้าและข้อมูลจะถูกส่งอีกครั้งโดยไม่ต้องกรอกแบบฟอร์มอีกครั้ง ฉันสามารถเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าอื่นหลังจากที่ส่งข้อความ แต่ฉันต้องการให้ผู้ใช้อยู่ในหน้าเดียวกัน

ฉันจำได้ว่าอ่านอะไรบางอย่างเกี่ยวกับการให้รหัสเซสชันที่ไม่ซ้ำกันของผู้ใช้แต่ละคนและเปรียบเทียบกับค่าอื่นซึ่งแก้ไขปัญหาที่ฉันมี แต่ฉันลืมว่ามันอยู่ที่ไหน



1
ทำไมคุณไม่ต้องการเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าอื่น
อดัม

@ อดัม: เพราะนี่เป็นสิ่งที่เกินกว่าที่จะขออีกครั้งไปยังเซิร์ฟเวอร์ซึ่งจะดึงข้อมูลบางส่วนจากฐานข้อมูลอีกครั้ง แต่นี่เป็นการสิ้นเปลืองทรัพยากรเพราะเราได้รับข้อมูลที่จำเป็นทั้งหมดแล้วขณะดำเนินการPOSTตามคำขอ
Eugen Konkov

@EugenKonkov ในรูปแบบ PRG คุณเพียงแค่เปลี่ยนเส้นทางไปยังหน้าเว็บที่แสดงข้อความสำเร็จ ไม่จำเป็นต้องดึงข้อมูลจากฐานข้อมูลเพิ่มเติม
อดัม

@ อดัม: คุณอาจแสดงระเบียนทั้งหมดที่สร้างขึ้นโดยPOSTข้อมูล ing ในกรณีนี้คุณต้องการSELECTจากฐานข้อมูล ตัวอย่างเช่นเมื่อคุณสร้างใบแจ้งหนี้คุณจะถูกนำไป/invoices/53ที่แสดงใบแจ้งหนี้ทั้งหมดแทนที่จะเป็นเพียง 'ความสำเร็จ'
Eugen Konkov

คำตอบ:


96

ใช้รูปแบบโพสต์ / เปลี่ยนเส้นทาง / รับ http://en.wikipedia.org/wiki/Post/Redirect/Get

ด้วยเว็บไซต์ของฉันฉันจะเก็บข้อความไว้ในคุกกี้หรือเซสชันเปลี่ยนเส้นทางหลังจากโพสต์อ่านคุกกี้ / เซสชันแล้วล้างค่าของเซสชันหรือตัวแปรคุกกี้นั้น


1
สิ่งนี้ทำให้ Chrome ใช้ไม่ได้สำหรับการพัฒนาที่ธุรกิจต้องการเพียงโพสต์เท่านั้น!
John Peters

26
หากคุณใช้รูปแบบ PRG คุณจะออกจากหน้าจริงหรือไม่ คำถามไม่ใช่วิธีทำให้สิ่งต่าง ๆ ทำงานไม่ได้เปลี่ยนเส้นทางหรือไม่
อดัม

1
ดูเหมือนว่าถ้าคุณเปลี่ยนเส้นทางไปที่หน้าเดียวกัน $ _POST จะถูกล้าง เมื่อฉันเข้าใจแล้วนั่นเป็นผลที่ต้องการ นั่นเป็นผลที่ฉันต้องการ ฉันคิดว่าคำตอบจะดีกว่าถ้ามันทำให้ชัดเจนว่า
donutguy640

ทำงานได้ดีคำแนะนำเดียวของฉันคือให้แน่ใจว่าคุณเปิดใช้งานการทดสอบข้อผิดพลาดอย่างเข้มงวดเพื่อให้คุณตรวจจับข้อผิดพลาดในขณะที่พัฒนามิฉะนั้นพวกเขาสามารถไปสังเกต
Maurice

ไม่ตอบคำถาม ไม่แน่ใจว่าทำไมเป็นคำตอบที่ยอมรับได้
YungGun

124

ฉันต้องการจะชี้ให้เห็นว่าคุณสามารถใช้วิธีการจาวาสคริปต์window.history.replaceStateเพื่อป้องกันการส่งซ้ำเมื่อรีเฟรชและปุ่มย้อนกลับ

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

ข้อพิสูจน์แนวคิดที่นี่: https://dtbaker.net/files/prevent-post-resubmit.php

ฉันยังคงแนะนำวิธี Post / Redirect / Get แต่นี่เป็นโซลูชัน JS ที่แปลกใหม่


1
ขอบคุณ @dtbaker มันยอดเยี่ยม :)
Gufran Hasan

1
Tks มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันมันแค่สร้าง 404 หน้าเพื่อหลีกเลี่ยงความเข้าใจผิดของผู้ใช้
tess hsu

น่าอัศจรรย์เพียง ขอบคุณ
user4906240

2
มันใช้งานไม่ได้ในซาฟารีเปลี่ยน href แต่ยังคงเก็บข้อมูลไว้กับคำขอโพสต์เพื่อส่ง
Vo Thanh Tung

สิ่งนี้ได้ผลสำหรับฉันขอบคุณ! ทำไมคุณถึงแนะนำวิธีการ PRG
iJassar

16

คุณควรใช้รูปแบบ Post Redirect Get เพื่อจัดการสิ่งนี้ แต่ถ้าคุณลงเอยในตำแหน่งที่ PRG ไม่สามารถใช้งานได้ (เช่นรูปแบบตัวเองอยู่ในการรวมการป้องกันการเปลี่ยนเส้นทาง) คุณสามารถแฮชพารามิเตอร์คำขอบางอย่างได้ เพื่อสร้างสตริงตามเนื้อหาจากนั้นตรวจสอบว่าคุณยังไม่ได้ส่ง

//create digest of the form submission:

    $messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);

//and check it against the stored value:

    $sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';

    if($messageIdent!=$sessionMessageIdent){//if its different:          
        //save the session var:
            $_SESSION['messageIdent'] = $messageIdent;
        //and...
            do_your_thang();
    } else {
        //you've sent this already!
    }

ขอขอบคุณที่แบ่งปัน แต่ดูเหมือนจะใช้งานไม่ได้ การรีเฟรชหน้านี้ส่งฟอร์มให้ฉันอีกครั้ง บางทีฉันหายไปบางอย่าง
aLearner

การรีเฟรชหน้าจะส่งทุกอย่างอีกครั้ง แต่เราเลือกที่จะประมวลผลข้อมูลการส่งหากหน้านั้นแตกต่างจากข้อมูลที่ส่งครั้งสุดท้าย (ซึ่งเราจัดเก็บไว้ในเซสชัน var 'messageIdent') คุณกำลังประมวลผลการส่งแบบฟอร์มของคุณภายในประโยค 'ถ้า messageIdents ต่างกัน' (เช่น 'do_your_thang ()' อยู่ที่ไหน)?
Moob

ขอบคุณสำหรับการตอบกลับของคุณ. ฉันลงเอยด้วยการนำรูปแบบ Post / Redirect / Get มาใช้ดังนั้นฉันจำไม่ได้แล้วว่าอะไรทำให้ฉันสะดุด ขอบคุณอีกครั้งสำหรับการวนกลับ
aLearner

วิธีนี้ไม่ได้มีไว้สำหรับบล็อกการส่งข้อมูลซ้ำ ... แต่เป็นการตรวจหาการส่งซ้ำเพื่อให้คุณสามารถเปลี่ยนรหัสของคุณเป็น "ทำ" ไม่ว่าคุณจะทำอะไรหากนี่เป็นการส่งสด ในคำอื่น ๆ : ด้วยวิธีนี้คุณสามารถตรวจสอบการส่ง "ต้นฉบับ" และวางข้อมูลของคุณ หากไม่ใช่ต้นฉบับอย่าวางข้อมูลของคุณ แสดงคำเตือน "dupe พยายาม" หรืออาจแสดง "การยืนยัน" แทน
TheSatinKnight

เพื่อให้สามารถใช้งานได้คุณจะต้องเริ่มเซสชันโดยการเพิ่มsession_start();ที่จุดเริ่มต้นของไฟล์ w3schools.com/php/php_sessions.aspพูดว่าหมายเหตุ: ฟังก์ชัน session_start () จะต้องเป็นสิ่งแรกในเอกสารของคุณ ก่อนแท็ก HTML ใด ๆ
wkille

16

ฉันใช้บรรทัดจาวาสคริปต์นี้เพื่อบล็อกป๊อปอัปขอให้ส่งแบบฟอร์มอีกครั้งเมื่อรีเฟรชเมื่อส่งแบบฟอร์มแล้ว

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}

เพียงวางบรรทัดนี้ที่ส่วนท้ายของไฟล์ของคุณและดูมายากล


จะเป็นรุ่นที่ดีที่ไม่สามารถปิดการใช้งานจากฝั่งไคลเอ็นต์ แต่สั้นง่ายเร็ว ... และทำสิ่งที่ต้องทำ เก็บประวัติเพื่อให้ผู้ใช้สามารถนำทางกลับโดยไม่ต้องส่งโพสต์ใหม่
PéterVértényi

16

คุณสามารถป้องกันการส่งแบบฟอร์มอีกครั้งผ่านตัวแปรเซสชัน

ก่อนอื่นคุณต้องตั้งค่าrand()ในกล่องข้อความและ$_SESSION['rand']ในหน้าแบบฟอร์ม:

<form action="" method="post">
  <?php
   $rand=rand();
   $_SESSION['rand']=$rand;
  ?>
 <input type="hidden" value="<?php echo $rand; ?>" name="randcheck" />
   Your Form's Other Field 
 <input type="submit" name="submitbtn" value="submit" />
</form>

หลังจากนั้นตรวจสอบ$_SESSION['rand']ด้วย$_POST['randcheck']ค่าช่องข้อความดังนี้:

if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
{
    // Your code here
}

3
เราสามารถใช้<input type="hidden" name="randcheck" id="randcheck" value="<?php echo microtime(); ?>" />แทน
Nikolay Bronskiy

ใช่เราสามารถใช้ microtime () เช่นเดียวกับ time () แทน rand () ไม่ว่าฟังก์ชันหรือตัวแปรใดที่ให้ค่าแตกต่างกันเราก็สามารถใช้ได้ แต่ตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่านั้นเป็นตัวแปร SESSION ที่นี่เซสชั่นจะต้องตรวจสอบกับฟิลด์ randcheck และเพื่อป้องกันไม่ให้ส่งแบบฟอร์มอีกครั้ง
Savoo

ไม่ควรล้างตัวแปรเซสชันหลังจากตรวจสอบว่าเซสชันและโพสต์ vars ตรงกันหรือไม่
denoise

1
@denoise ฉันเชื่อว่าความคิดโดย @Savoo คือหลังจาก$_POSTที่ข้อมูลในรูปแบบหน้าเดียวกันโหลดซ้ำการตั้งค่าเซสชั่นและโพสต์ตัวแปรอีกครั้ง การสร้างตัวแปรควรเกิดขึ้นหลังจากตรวจสอบว่าตัวแปรตรงกันหรือไม่ ดังนั้นจึงunsetไม่จำเป็น
HalfMens

13

เมื่อมีการประมวลผลแบบฟอร์มคุณเปลี่ยนเส้นทางไปยังหน้าอื่น:

... process complete....
header('Location: thankyou.php');

คุณสามารถเปลี่ยนเส้นทางไปยังหน้าเดียวกันได้

หากคุณกำลังทำอะไรบางอย่างเช่นความคิดเห็นและคุณต้องการให้ผู้ใช้อยู่ในหน้าเดียวกันคุณสามารถใช้ Ajax เพื่อจัดการกับการส่งแบบฟอร์ม


12

ฉันพบวิธีแก้ไขปัญหาถัดไป คุณสามารถหลีกเลี่ยงการเปลี่ยนเส้นทางหลังจากดำเนินการPOSTตามคำขอโดยจัดการhistoryวัตถุ

ดังนั้นคุณมีรูปแบบ HTML:

<form method=POST action='/process.php'>
 <input type=submit value=OK>
</form>

เมื่อคุณประมวลผลแบบฟอร์มนี้บนเซิร์ฟเวอร์ของคุณคุณแทนที่จะเปลี่ยนเส้นทางผู้ใช้ไปยัง/the/result/pageโดยการตั้งค่าLocationส่วนหัวเช่นนี้:

$cat process.php
<?php 
     process POST data here
     ... 
     header('Location: /the/result/page');
     exit();
?>

ป้อนคำอธิบายรูปภาพที่นี่

หลังจากประมวลผลPOSTข้อมูล ed คุณแสดงผลขนาดเล็ก<script>และผลลัพธ์/the/result/page

<?php 
     process POST data here
     render the <script>         // see below
     render `/the/result/page`   // OK
?>

<script>คุณควรทำให้:

<script>
    window.onload = function() {
        history.replaceState("", "", "/the/result/page");
    }
</script>

ผลลัพธ์คือ:

ป้อนคำอธิบายรูปภาพที่นี่

ในขณะที่คุณสามารถดูข้อมูลแบบฟอร์มถูกPOSTเอ็ดprocess.phpสคริปต์
สคริปต์นี้กระบวนการPOSTed ข้อมูลและแสดงผล/the/result/pageได้ในครั้งเดียวด้วย:

  1. ไม่มีการเปลี่ยนเส้นทาง
  2. ไม่มีPOSTข้อมูลอีกเมื่อคุณรีเฟรชหน้า (F5)
  3. ไม่POSTเมื่อคุณนำทางไปยังหน้าก่อนหน้า / ถัดไปผ่านประวัติเบราว์เซอร์

UPD

ฉันขอให้ฟีเจอร์ขอให้ทีมMozilla FireFoxช่วยให้ผู้ใช้สามารถตั้งค่าNextPageส่วนหัวซึ่งจะทำงานเหมือนLocationส่วนหัวและสร้างpost/redirect/getรูปแบบล้าสมัย

ในระยะสั้น เมื่อเซิร์ฟเวอร์ประมวลผลPOSTข้อมูลในแบบฟอร์มสำเร็จแล้ว:

  1. ตั้งค่าNextPageส่วนหัวแทนLocation
  2. แสดงผลลัพธ์ของการประมวลผลPOSTข้อมูลในแบบฟอร์มที่จะแสดงผลสำหรับการGETร้องขอในpost/redirect/getรูปแบบ

เบราว์เซอร์ในทางกลับกันเมื่อเห็นNextPageส่วนหัว:

  1. ปรับwindow.locationด้วยNextPageค่า
  2. เมื่อผู้ใช้รีเฟรชหน้าเบราว์เซอร์จะเจรจาGETขอNextPageแทนPOSTข้อมูลแบบฟอร์มใหม่

ฉันคิดว่าสิ่งนี้จะยอดเยี่ยมหากใช้งานจะไม่? =)


11
  1. ใช้ส่วนหัวและเปลี่ยนเส้นทางหน้า

    header("Location:your_page.php"); คุณสามารถเปลี่ยนเส้นทางไปยังหน้าเดียวกันหรือหน้าอื่น

  2. เลิกตั้ง $ _POST หลังจากแทรกลงในฐานข้อมูล

    unset($_POST);


54
การยกเลิกการตั้งค่า $ _POST จะไม่มีผลกับการส่งแบบฟอร์มอีกเลยอย่างน้อยไม่ใช่ใน Chrome
Gavin

2
มันจะไม่ทำงาน เมื่อผู้ใช้ไปที่หน้าย้อนกลับผู้ใช้จะทำการตั้งค่าตัวแปร POST อีกครั้ง
Sandhu

เหตุผลในการใช้unsetคืออะไร โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณโดยที่คนอื่นสามารถเรียนรู้ได้จากมัน
Nico Haase

7

วิธีที่ค่อนข้างแน่นอนคือการติดตั้ง ID เฉพาะลงในโพสต์และแคชใน

<input type='hidden' name='post_id' value='".createPassword(64)."'>

จากนั้นในรหัสของคุณทำสิ่งนี้:

if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
    $_SESSION['post_id'] = $_POST['post_id'];
    //do post stuff
} else {
    //normal display
}

function createPassword($length)
{
    $chars = "abcdefghijkmnopqrstuvwxyz023456789";
    srand((double)microtime()*1000000);
    $i = 0;
    $pass = '' ;

    while ($i <= ($length - 1)) {
        $num = rand() % 33;
        $tmp = substr($chars, $num, 1);
        $pass = $pass . $tmp;
        $i++;
    }
    return $pass;
}

ที่จริงฉันเพิ่งเขียนอะไรบางอย่างที่คล้ายกันนี้ แต่ไม่ได้ผ่านปัญหาในการสร้างรหัสผ่านฉันเพิ่งระบุแบบฟอร์มของฉัน (เช่นขั้นตอนที่ 1-5) ดังนั้นหากพวกเขาเท่ากันเราก็จะดำเนินต่อไป มิฉะนั้นจะไม่บันทึกลงในฐานข้อมูลหรือส่งอีเมล แต่ให้ผู้ใช้ลงจอดที่ใดก็ตามที่จะพาเขาไป
Fernando Silva

1
ฉันคิดว่านี่เป็นทางออกที่ดีกว่าการโหลดหน้าเว็บอีกครั้งเนื่องจากฉันแสดงข้อความเมื่อโพสต์ประสบความสำเร็จและการโหลดหน้าซ้ำจะลบข้อความ งานนี้เสียดสีสำหรับฉันคุณยังสามารถใช้ uniqid ได้
Julio Popócatl

6

วิธีนี้ใช้ได้ดีกับฉันและฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดในการทำงานนี้

แนวคิดทั่วไปคือการเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าอื่น ๆ หลังจากส่งแบบฟอร์มซึ่งจะหยุดการส่งแบบฟอร์มอีกครั้งในการรีเฟรชหน้า อย่างไรก็ตามหากคุณต้องการให้ผู้ใช้ค้างไว้ในหน้าเดียวกันหลังจากส่งแบบฟอร์มคุณสามารถทำได้หลายวิธี แต่ที่นี่ฉันจะอธิบายวิธีการจาวาสคริปต์

วิธี Javascript

วิธีนี้ค่อนข้างง่ายและบล็อกป๊อปอัปขอให้ส่งแบบฟอร์มอีกครั้งเมื่อรีเฟรชเมื่อส่งแบบฟอร์ม เพียงวางโค้ดจาวาสคริปต์ในส่วนท้ายของไฟล์ของคุณและดูเวทมนต์

<script>
if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}
</script>


นี่ช่วยฉันด้วย
Ankit

4

จาวาสคริ

วิธีนี้ค่อนข้างง่ายและบล็อกป๊อปอัปขอให้ส่งแบบฟอร์มอีกครั้งเมื่อรีเฟรชเมื่อส่งแบบฟอร์ม เพียงวางโค้ดจาวาสคริปต์ในส่วนท้ายของไฟล์ของคุณและดูเวทมนต์

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

3

เพียงเปลี่ยนเส้นทางไปยังหน้าเดียวกันหลังจากใช้ข้อมูลในแบบฟอร์มและใช้งานได้ ฉันได้ลองแล้ว

header('location:yourpage.php');

4
นี่เป็นเพียงการทำซ้ำคำตอบเดียวกับที่คนอื่นให้ไว้เมื่อหลายปีก่อน (อันที่จริงอีกสองคน!)
นิคไรซ์

หากคุณทำซ้ำคำตอบของคนอื่นอย่างน้อยคุณควรเพิ่มคำอธิบายลงในคำตอบของคุณเพื่อให้น่าสนใจ
Nico Haase

3

โพสต์ของ Moob เวอร์ชันที่ได้รับการปรับปรุง สร้างแฮชของ POST บันทึกเป็นคุกกี้เซสชันและเปรียบเทียบแฮชทุกเซสชัน

// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );

$post_hash = md5( json_encode( $_POST ) );

if( session_start() )
{
    $post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
    $_SESSION[ 'post_hash' ] = $post_hash;
    session_write_close();
}
else
{
    $post_resubmitted = false;
}

if ( $post_resubmitted ) {
  // POST was resubmitted
}
else
{
  // POST was submitted normally
}

2

โดยทั่วไปคุณต้องเปลี่ยนเส้นทางจากหน้านั้น แต่ก็ยังสามารถสร้างปัญหาได้ในขณะที่อินเทอร์เน็ตของคุณช้า (เปลี่ยนเส้นทางส่วนหัวจากเซิร์ฟเวอร์ด้าน)

ตัวอย่างสถานการณ์พื้นฐาน:

คลิกที่ปุ่มส่งสองครั้ง

วิธีแก้ปัญหา

  • ด้านลูกค้า

    • ปิดการใช้งานปุ่มส่งเมื่อลูกค้าคลิกที่มัน
    • หากคุณใช้ Jquery: Jquery.one
    • รูปแบบ PRG
  • ฝั่งเซิร์ฟเวอร์

    • การใช้การแบ่งแยกการประทับเวลาตาม / การประทับเวลาที่แตกต่างเมื่อส่งคำขอ
    • โทเค็น Userequest เมื่อโหลดหลักขึ้นแล้วให้กำหนดคำขอชั่วคราวซึ่งหากถูกทำซ้ำจะถูกละเว้น

2

วิธีการป้องกันการส่งแบบฟอร์ม php อีกครั้งโดยไม่เปลี่ยนเส้นทาง หากคุณใช้ $ _SESSION (หลัง session_start) และแบบฟอร์ม $ _POST คุณสามารถทำสิ่งนี้:

if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
  // do your stuff, save data into database, etc
}

ในรูปแบบ html ของคุณให้ใส่สิ่งนี้:

<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
    if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
        $_SESSION['act'] = 1;
    } else {
        $_SESSION['act'] = 2;
    }
}
?>

ดังนั้นทุกครั้งที่มีการส่งแบบฟอร์มจะมีการสร้างการกระทำใหม่จัดเก็บในเซสชันและเปรียบเทียบกับการกระทำที่โพสต์

Ps: ถ้าคุณใช้แบบฟอร์มรับคุณสามารถเปลี่ยน POST ทั้งหมดด้วย GET และใช้งานได้เช่นกัน


1

หลังจากแทรกลงในฐานข้อมูลให้เรียกวิธี unset () เพื่อล้างข้อมูล

ไม่มีการตั้งค่า ($ _ POST);

เพื่อป้องกันการแทรกข้อมูลรีเฟรชทำหน้าเปลี่ยนเส้นทางไปยังหน้าเดียวกันหรือหน้าอื่นหลังจากบันทึกแทรก

ส่วนหัว ( 'ตำแหน่งที่ตั้ง:' $ _ SERVER [ 'PHP_SELF'].);


1
โปรดเพิ่มคำอธิบายลงในคำตอบของคุณเพื่อให้คนอื่นสามารถเรียนรู้จากมัน - เหตุใดจึงunsetต้องมีการโทร จะเกิดอะไรขึ้นถ้าคุณข้ามไป
Nico Haase

0

การใช้รูปแบบโพสต์ / เปลี่ยนเส้นทาง / รับจาก Keverw เป็นความคิดที่ดี อย่างไรก็ตามคุณไม่สามารถอยู่ในหน้าของคุณได้ (และฉันคิดว่านี่เป็นสิ่งที่คุณขอ?) นอกจากนี้บางครั้งอาจล้มเหลว :

หากผู้ใช้เว็บรีเฟรชก่อนที่การส่งครั้งแรกจะเสร็จสมบูรณ์เนื่องจากเซิร์ฟเวอร์ล้าส่งผลให้มีการร้องขอ HTTP POST ซ้ำในตัวแทนผู้ใช้บางราย

ตัวเลือกอื่นจะเก็บไว้ในเซสชันหากข้อความควรถูกเขียนลงในฐานข้อมูล SQL ของคุณเช่นนี้:

if($_SERVER['REQUEST_METHOD'] != 'POST')
{
  $_SESSION['writeSQL'] = true;
}
else
{
  if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
  {
    $_SESSION['writeSQL'] = false;

    /* save $_POST values into SQL */
  }
}

0

อย่างที่คนอื่น ๆ พูดกันคุณไม่สามารถใช้โพสต์ / เปลี่ยนเส้นทาง / รับได้ แต่ในเวลาเดียวกันมันค่อนข้างง่ายที่จะทำสิ่งที่คุณต้องการทำฝั่งเซิร์ฟเวอร์

ในหน้าโพสต์ของคุณคุณเพียงแค่ตรวจสอบการป้อนข้อมูลของผู้ใช้ แต่ไม่ดำเนินการใด ๆ กับมันแทนคุณคัดลอกลงในอาร์เรย์ SESSION จากนั้นคุณเปลี่ยนเส้นทางกลับไปที่หน้าการส่งหลักอีกครั้ง หน้าการส่งหลักของคุณเริ่มต้นด้วยการตรวจสอบเพื่อดูว่ามีเซสชัน SESSION ที่คุณใช้อยู่หรือไม่และคัดลอกไปยังอาร์เรย์ภายในเครื่องแล้วยกเลิกการตั้งค่า จากตรงนี้คุณสามารถลงมือทำ

วิธีนี้คุณจะทำงานหลักทั้งหมดของคุณเพียงครั้งเดียวบรรลุสิ่งที่คุณต้องการจะทำ


0

ฉันค้นหาวิธีแก้ปัญหาเพื่อป้องกันการส่งซ้ำในโครงการขนาดใหญ่หลังจากนั้น รหัสทำงานได้ดีกับ $ _GET และ $ _POST และฉันไม่สามารถเปลี่ยนพฤติกรรมองค์ประกอบของแบบฟอร์มได้โดยไม่ต้องเสี่ยงกับข้อผิดพลาดที่ไม่คาดคิด ดังนั้นนี่คือรหัสของฉัน:

<!-- language: lang-php -->
<?php

// Very top of your code:

// Start session:
session_start();

// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
    // Store Post Form Data in Session Variable
    $_SESSION["POST"] = $_POST;
    // Reload Page if there were no outputs
    if ( ! headers_sent() ) {
        // Build URL to reload with GET Parameters
        // Change https to http if your site has no ssl
        $location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        // Reload Page
        header( "location: " . $location, true, 303 );
        // Stop any further progress
        die();
    }
}

// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
    $_POST = $_SESSION["POST"];
    // Tell PHP that POST is sent
    $_SERVER['REQUEST_METHOD'] = 'POST';
}

// Your code:
?><html>
    <head>
        <title>GET/POST Resubmit</title>
    </head>
    <body>

    <h1>Forms:</h1>
    <h2>GET Form:</h2>
    <form action="index.php" method="get">
        <input type="text" id="text_get" value="test text get" name="text_get"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form:</h2>
    <form action="index.php" method="post">
        <input type="text" id="text_post" value="test text post" name="text_post"/>
        <input type="submit" value="submit">
    </form>
    <h2>POST Form with GET action:</h2>
    <form action="index.php?text_get2=getwithpost" method="post">
        <input type="text" id="text_post2" value="test text get post" name="text_post2"/>
        <input type="submit" value="submit">
    </form>
    <h2>File Upload Form:</h2>
    <form action="index.php" method="post" enctype="multipart/form-data">
        <input type="file" id="file" name="file">
        <input type="submit" value="submit">
    </form>

    <h1>Results:</h1>
    <h2>GET Form Result:</h2>
    <p>text_get: <?php echo $_GET["text_get"]; ?></p>
    <h2>POST Form Result:</h2>
    <p>text_post: <?php echo $_POST["text_post"]; ?></p>
    <h2>POST Form with GET Result:</h2>
    <p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
    <p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
    <h2>File Upload:</h2>
    <p>file:
    <pre><?php if ( ! empty( $_FILES ) ) {
            echo print_r( $_FILES, true );
        } ?></pre>
    </p>
    <p></p>
    </body>
    </html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );

มันทำงานเพื่อหลีกเลี่ยงการส่ง $ _POST อีกครั้งไม่ใช่ $ _GET แต่นี่คือพฤติกรรมที่ฉันต้องการ ปัญหาการส่งซ้ำไม่ทำงานกับการอัปโหลดไฟล์!


0

การทำงานสำหรับฉันคืออะไร:

if ( !refreshed()) {
   //Your Submit Here
        if (isset( $_GET['refresh'])) {
            setcookie("refresh",$_GET['refresh'], time() + (86400 * 5), "/");
        }

    }    
}


function refreshed()
{
    if (isset($_GET['refresh'])) {
        $token = $_GET['refresh'];
        if (isset($_COOKIE['refresh'])) {
            if ($_COOKIE['refresh'] != $token) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}  


function createToken($length) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}

?>

และในแบบฟอร์มของคุณ

 <form  action="?refresh=<?php echo createToken(3)?>">



 </form>

0

form.phpตัวอย่างนี้แสดงวิธีการใช้ PRG ให้ถูกต้อง (เมื่อฟอร์มถูกต้องหรือไม่)

  • มันเปลี่ยนเส้นทางไปยังหน้าเดียวกันเฉพาะเมื่อแบบฟอร์มที่ถูกต้องและดำเนินการ
  • การเปลี่ยนเส้นทางปกป้องฟอร์มจากการถูกส่งซ้ำในการรีเฟรชหน้า
  • มันใช้เซสชันเพื่อไม่ให้ข้อความที่ประสบความสำเร็จหลวมที่คุณต้องการแสดงเมื่อฟอร์มถูกต้อง
  • มีสองปุ่มสำหรับการทดสอบ: "ส่งที่ถูกต้อง", "ส่งไม่ถูกต้อง" ลองและรีเฟรชหน้าหลังจากนั้น
<?php
session_start();

function doSelfRedirect()
{
  header('Location:'.$_SERVER['PHP_SELF']);
  exit;
}

function setFlashMessage($msg)
{
  $_SESSION['message'] = $msg;
}

function getFlashMessage()
{
  if (!empty($_SESSION['message'])) {
    $msg = $_SESSION['message'];
    unset($_SESSION['message']);
  } else {
    $msg = null;
  }

  return $msg;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  // Validation primitive example.
  if (empty($_POST['valid'])) {
    $formIsValid = false;
    setFlashMessage('Invalid form submit');
  } else {
    $formIsValid = true;
  }

  if ($formIsValid) {
    // Perform any actions here.
    // ...

    // Cool!
    setFlashMessage('Form is valid. Action performed.');

    // Prevent form resubmission.
    doSelfRedirect();
  }
}
?>
<h1>Hello form</h1>

<?php if ($msg = getFlashMessage()): ?>
  <div><?= $msg ?></div>
<?php endif; ?>

<form method="post">
  <input type="text" name="foo" value="bar"><br><br>
  <button type="submit" name="invalid" value="0">Invalid submit</button>
  <button type="submit" name="valid" value="1">Valid submit</button>
</form>

-2
if (($_SERVER['REQUEST_METHOD'] == 'POST') and (isset($_SESSION['uniq']))){
    if($everything_fine){
        unset($_SESSION['uniq']);
    }
}
else{
    $_SESSION['uniq'] = uniqid();
}

โปรดเพิ่มคำอธิบายลงในคำตอบของคุณเพื่อให้คนอื่นสามารถเรียนรู้จากมัน - $everything_fineมาจากไหน?
Nico Haase

-3

ทำไมไม่ใช้$_POST['submit']ตัวแปรเป็นคำสั่งแบบลอจิคัลเพื่อบันทึกสิ่งที่อยู่ในรูปแบบ คุณสามารถเปลี่ยนเส้นทางไปยังหน้าเดียวกัน (ในกรณีที่พวกเขาฟื้นฟูและเมื่อพวกเขาตีgo backในเบราว์เซอร์ส่งตัวแปรโพสต์จะไม่สามารถตั้งค่าอีกต่อไป. เพียงให้แน่ใจว่าคุณปุ่มส่งมีnameและของidsubmit


1
ลองดูที่en.wikipedia.org/wiki/Post/Redirect/Get ! นี่คือแนวทางที่ถูกต้อง
jan267
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.