I want to send a post request with a url redirect to a request page. Jest think request page currently use for handle submit form.
I tried the following code to my request page.
<?php
$myFile = "test.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
$stringData = "Request come to the page\n";
fwrite($fh, $stringData);
if (isset($_POST)) {
$stringData = $_POST['user'];
fwrite($fh, $stringData);
}
fclose($fh);
echo 'page found';
I tried Zend_Http_Client to do that. This is my simple action.
public function indexAction()
{
$client = new Zend_Http_Client('http://localhost/test/test.php');
$client->setParameterPost(array('user' => 'dinuka'));
$client->setConfig(array('strictredirects' => true));
$response = $client->request(Zend_Http_Client::POST);
}
Now request send to the test.php. But not redirect to the http://localhost/test/test.php page. I want send request + redirect. I asked this question previously. But it closed as pure question. Please help me. I haven't good knowledge about http request. What is the strictredirects?
I think this might cover the basics of what you want:
<?php
class IndexController extends Zend_Controller_Action {
public function init() {
}
public function indexAction() {
//set form action to indexController nextAction
$form = My_Form();
$form->setAction('/index/next');
//asign form to view
$this->view->form = $form;
}
public function nextAction() {
//if form is posted and valid
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost())) {
$data = $form->getValues();
//Do some stuff
}
} else {
//if form not posted go to form in indexAction
$this->_forward('index');
}
}
}
it seems as though this the form of your question, but what you really want to know is how send post data in a redirect instead of get data, if I'm on the right track please
comment on how else we can change this to help you solve your problem.
public function indexAction()
{
$client = new Zend_Http_Client('http://localhost/test/test.php');
$client->setParameterPost(array('user' => 'dinuka'));
$client->setConfig(array('strictredirects' => true));
$response = $client->request(Zend_Http_Client::POST);
}
I get the idea that what you want with this piece of code is to submit a post request to this url and to redirect your browser there at the same time.
This should be possible and according to what I can find it is supposed to be as simple as $response->location but I can't make it work. ->location is supposed to be a header element but I can't find it. Maybe one of our other gurus can help.
Related
Here's my setup for an email contact form:
www.example.com/includes/contact_form.php
www.example.com/includes/contact_submit.php
www.example.com/contact/
/contact/ includes contact_form.php, and the form points to contact_submit.php to run.
When contact_submit.php successfully sends the mail, it does a redirect back to /contact/ but includes a $_GET variable.
header('Location: /contact/index.php?success=yup');
Then in contact_form.php I have:
if (isset($_GET['success'])) { echo 'Your message has been received etc'; exit(); }
Everything works fine. I made it this way so that the form couldn't be F5/refresh resubmitted, and it is successful in that.
However, anyone can access the success page at any time by manually entering the url, even if they don't submit the form. Is there any way around that?
Ofcourse.
Use sessions for that:
class ResponseLog {
private function __construct(){}
public static function hasMessages(){
return (isset($_SESSION['response']['messages']) && !empty($_SESSION['response']['messages'])) ? true : false;
}
public static function setResponse(array $response){
$_SESSION['response'] = $response;
}
public static function getLastResponse(){
$response = isset($_SESSION['response'])) ? $_SESSION['response'] : null;
#unset($_SESSION['response']);
return $response;
}
}
And use it like this:
if(isset($_POST['form'])){
//validation and all to proccess request goes here
if(!$valid){
$response = array('request' => $_POST,'messages' => array('Incorrect email','Please enter forename'),'url' => '/my/form/where/it/happen/');
}
else {
$response = array('messages' => array('Success'),'url' => '/my/form/where/it/happen/');
}
ResponseLog::setResponse($response);
//redirect to contact form
}
In success page or fail:
if(ResponseLog::hasMessages()){
$response = ResponseLog::getLastResponse();
foreach($response['messages'] as $message){
echo $message;
}
}
With this you can store everything user does and can work with data as you need.
I hope this help :)
Warn: I wrote it from mind, so it's untested code and it can be implemented better it's just for view how to work with user session and responses.
PS: But is a lot of ways how to do it, for example see flash messages in some framework and you will be see how it works with sessions etc.
You can use the referrer page if you want, and throw an error or redirect if it is not the form page, but it is not so good. You can also check whether the fields and form name have been posted.
$_SERVER['HTTP_REFERER']
I am trying to create an ajax login script but have hit a wall. I hav built one before but now using the cakephp framwework.
I'm not really sure ho to go about this. At the moment I have a login function in the controller,
public function login()
{
if($this->request->is('post')) {
if($this->Auth->login()) {
$this->Session->setFlash('Login Passed');
} else {
$this->Session->setFlash('Login Failed');
}
}
}
Do i then use ajax to send values to this from the form? These lines are from my old (non-cakephp) system,
xmlhttp.open("POST","http://www.site.com/login/",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("AttemptLogin=true&AccountEmail="+ userMail +"&AccountPassword=" + userPass);
Should i modify them in any way? Also, how do i handle any validations and login attempts with errorsetc.
Sorry about the question being quite open ended and long but i don't know where to go,I have looked for tutorials but can't find any.
Many Thanks
Chris
You can use javascript helper from cake and have one template that converts
the response to the json format, in the controller just include the helper:
var $helpers = array('Javascript');
var $components = array('RequestHandler');
//the template ie "/views/templates/ajax.ctp"
echo $javascript->object(isset($response) ? $response : array());
So yo can set you function like:
public function login()
{
if($this->RequestHandler->isPost()) {
if($this->Auth->login()) {
$response('success'=>true);
} else {
$response('success'=>false);
}
$this->set('response', $response);
$this->render(null, 'ajax');
}
And the javascript i recommend jQuery
$.ajax({url:"/controller/login",type:"POST", data:$('#formLogin').serialize(), dataType:"json", success:responseLogin, context:this});
function responseLogin(response)
{
//here is the object returned by cakephp
if(!response.success)
//do something the user don't login
else
//do something the user pass the login
}
I've been having problems created modular reusable components in my Zend Framework app. In this case I'm not referring to Zend Framework modules but rather the ability to have a reusable MVC widgety thing if you like. The problems I'm having may be very particular to my implementation, but I'm completely happy to throw it out and start again if someone can point me in the right direction. Anyway, specifics and code will hopefully explain things better and even if what I'm doing is not the best way it should show what I'm trying to achieve:
A simple example is a Mailing List sign up form. I want to include this on several pages of the site which use different Controllers and this presents a few problems in how to process the data and return relevant messages. I don't want to do either of the following as they really smell:
Create a base controller with the form processing in and extend (Bad)
Duplicate form processing code in relevant controllers (Even worse!)
The clean way to go feels to me to create a new Controller to process the mailing list form data, use a View Helper to easily output the form and relevant markup into the desired pages and then redirect back to the page where signup occurred once the form has been processed. However, I'd like to use the form validation provided by Zend_Form, which means I'd need to pass the form object back to the view helper somehow if validation fails but in the same request. I'm currently doing this by setting it as a variable on the view and then forwarding back to the previous page rather than redirecting, which is ok(ish). If validation is ok then I'd prefer to use a redirect back to the original page. I'm having trouble doing this though as I'd like to pass messages back to the component about the state of signup. Normally I'd use the FlashMessenger Action Helper, I could namespace it in this case so messages didn't clash with other page data, but I can't access it from within a View Helper. So currently I'm forwarding in this case too. I'd much prefer a redirect to prevent form resubmissions if a user refreshes the page and to keep the URL clean. I realise I essentially want to have a mini MVC dispatch process within a page and I think that's what the action stack is for? I really don't know much about this though and any pointers would be greatly appreciated. Here's my current code:
Controller:
<?php
class MailingListController extends Zend_Controller_Action {
public function insertAction() {
$request = $this->getRequest();
$returnTo = $request->getParam('return_to');
if(!$request->isPost() || (!isset($returnTo) || empty($returnTo))) {
$this->_redirect('/');
}
$mailingList = new Model_MailingList();
$form = new Form_MailingList();
$returnTo = explode('/', $returnTo);
if($form->isValid($_POST)) {
$emailAddress = $form->getValue('email_address');
$mailingList->addEmailAddress($emailAddress);
$this->view->mailingListMessages = $mailingList->getMessages();
$this->view->mailingListForm = "";
}
else {
$this->view->mailingListForm = $form;
}
$this->_forward($returnTo[2], $returnTo[1], $returnTo[0]);
}
}
return_to is a string containing the current URI (module/controller/action), which is generated in the View Helper. I'd prefer to redirect inside the $form->isValid($_POST) block.
View Helper:
<?php
class Zend_View_Helper_MailingList extends Zend_View_Helper_Abstract {
public function mailingList($form, $messages = "") {
if(!isset($form)) {
$request = Zend_Controller_Front::getInstance()->getRequest();
$currentPage = $request->getModuleName() . '/' . $request->getControllerName() . '/' . $request->getActionName();
$form = new Form_MailingList();
$form->setAction('/mailing-list/insert');
$form->setCurrentPage($currentPage);
}
$html = '<div class="mailingList"><h2>Join Our Mailing List</h2>' . $form;
$html .= $messages;
$html .= '</div>';
return $html;
}
}
Getting an instance of the Front Controller in the View Helper isn't ideal but I'd prefer to encapsulate as much as possible.
If I have a form object where validation has failed I can pass it back into the helper to output with error messages. If I have some messages to render I can also pass them into the helper.
In my view scripts I'm using the helper like so:
<?=$this->mailingList($this->mailingListForm, $this->mailingListMessages);?>
If neither mailingListForm or mailingListMessages has been set on the view by MailingListController, it will output a new form with no messages.
Any help is greatly appreciated!
Using ajax seems to be an optimal way. View Action Helper is used only for the first load of the mailing form.
Controller
class MailingListController extends Zend_Controller_Action {
public function insertAction() {
$request = $this->getRequest();
$form = new Form_MailingList();
if ($request->isPost()) {
if ($form->isValid($request->getPost())) {
$mailingList = new Model_MailingList();
$emailAddress = $form->getValue('email_address');
$mailingList->addEmailAddress($emailAddress);
$form = $mailingList->getMessages();
}
}
$this->view->form = $form;
}
}
view script insert.phtml
<?php echo $this->form; ?>
Form class
class Form_MailingList extends Zend_Form {
public function init() {
//among other things
$this->setAttrib('id', 'mailing-list-form');
$this->setAction('/mailing-list/insert');
}
}
View Helper
class Zend_View_Helper_MailingList extends Zend_View_Helper_Abstract {
public function mailingList() {
$this->view->headScript()->appendFile('/js/mailing-list.js');
return '<div id="mailing-list-wrap">' . $this->view->action('insert', 'mailing-list') . '</div>';
}
}
JS file mailing-list.js
$(document).ready(function() {
$('#mailing-list-form').submit(function() {
var formAction = $(this).attr('action');
var formData = $(this).serialize();
$.post(formAction, formData, function(data) {
//response going in form's parent container
$(this).parent().html(data);
});
return false;
});
});
I think the way you've done it is pretty close to what I would do. If you set aside the requirement of wanting to display the Zend_Form error messages in the page, then what you do instead is:
The view helper just displays the form (it doesn't need to take the form object or messages as parameters)
The form submits to your other controller as it does now
The mailing list controller redirects (instead of forwarding) back to the return URL on success
The mailing list controller redisplays the form on its own, along with errors on failure
This makes everything much simpler, the only issue is that if there are any validation errors then the user loses their context and gets a plain old page with the form on instead of where they were. You can then address this (either now or at a later date) by changing the form to submit via. Ajax instead, and rendering the errors via. JS. But this would be a fair amount of work.
OK, I've come up with a solution that I feel happier about and solves some of the problems I was facing. Hopefully, this might help someone out who's facing similar issues. The only downside now is that I'm referencing the Model inside the View Helper. Not loose coupling I know but I've seen this done several times before and it's even recommended in the ZF docs as a way to avoid using the 'action' view helper (which will create a new MVC dispatch loop). On the whole, I think the DRYness and encapsulation is worth it, there's probably some other suitable lingo too.
In order to be able to use a redirect back from my MailingListController but maintain the messages from my model and any form validation errors I need to store them in the session. For messages I'd normally use the FlashMessenger action helper, but as getting hold of this in a View Helper is not best practice, it won't handle my form errors and all it's really doing is saving stuff to the session anyway it's unnecessary. I can implement my own session storage in the Model_MailingList, which I can also use for the form errors. I can then repopulate the form with the errors after the redirect and print out any relevant messages. Anyway, here's the code:
Controller:
<?php
class MailingListController extends Zend_Controller_Action {
public function insertAction() {
$request = $this->getRequest();
$returnTo = $request->getParam('return_to');
if(!$request->isPost() || (!isset($returnTo) || empty($returnTo))) {
$this->_redirect('/');
}
$mailingList = new Model_MailingList();
$form = new Form_MailingList();
if($form->isValid($_POST)) {
$emailAddress = $form->getValue('email_address');
$mailingList->addEmailAddress($emailAddress);
}
else {
$mailingList->setFormErrors($form->getMessages());
}
$redirect = rtrim($request->getBaseUrl(), '/') . $returnTo;
$this->_redirect($redirect);
}
}
I've added a method to my Model_MailingList class; setFormErrors($errors) that I pass the error messages from the form if it fails validation. This saves the error array to the session.
I normally use a base model class that has addMessage and getMessages methods. These just access a protected array of messages. In my Model_MailingList I override these methods to store the messages in the session instead. In the addEmailAddress($emailAddress) method I'm already calling addMessage to say whether inserting the email address to the db has been successful.
Model:
<?php
class Model_MailingList extends Thinkjam_Model_DbAbstract {
private $_session;
public function __construct() {
$this->_session = new Zend_Session_Namespace(__CLASS__);
}
public function setFormErrors($errors) {
$this->_session->formErrors = $errors;
}
public function getFormErrors() {
$errors = array();
if(isset($this->_session->formErrors)) {
$errors = $this->_session->formErrors;
unset($this->_session->formErrors);
}
return $errors;
}
// override addMessage and getMessages
protected function addMessage($message) {
if(!isset($this->_session->messages)) {
$this->_session->messages = array();
}
$this->_session->messages[] = $message;
}
public function getMessages() {
if(isset($this->_session->messages)) {
$this->_messages = $this->_session->messages;
unset($this->_session->messages);
}
return $this->_messages;
}
…
public function addEmailAddress($emailAddress) {
...
// I call this if db insert was successful:
$this->addMessage("Thank you. You have been successfully added to the mailing list.")
}
}
I now don't need to pass any params to the view helper as it can query it's state from the Model directly. $this->view->messenger is just another view helper that converts an array to an unordered list.
View Helper:
<?php
class Zend_View_Helper_MailingList extends Zend_View_Helper_Abstract {
private $_mailingList;
public function MailingList() {
$this->_mailingList = new Model_MailingList();
return $this;
}
public function getForm() {
$request = Zend_Controller_Front::getInstance()->getRequest();
$currentPage = '/' . $request->getModuleName() . '/' . $request->getControllerName() . '/' . $request->getActionName();
$form = new Form_MailingList();
$form->setAction('/mailing-list/insert');
$form->setCurrentPage($currentPage);
$form->setErrors($this->_mailingList->getFormErrors());
$html = '<div class="mailingList"><h2>Join Our Mailing List</h2>' . $form;
$html .= $this->view->messenger($this->_mailingList->getMessages());
$html .= '</div>';
return $html;
}
}
Then in the Form_MailingList class I just need to add an additional method to repopulate the error messages. Although getMessages() is a method of Zend_Form there doesn't appear to be any corresponding setMessages(). You can do this on a Zend_Form_Element however, so I've added the following function to the Form_MailingList class:
Form:
<?php
class Form_MailingList extends Thinkjam_Form_Abstract {
...
public function setErrors(array $errors) {
foreach($errors as $key => $value) {
$this->getElement($key)->setErrors($value);
}
}
}
I can now add a signup form on any page of my site using the MailingList view helper:
<?=$this->MailingList()->getForm();?>
I realise a lot of the problems I was facing was down to a very specific set of circumstances, but hopefully this can help some other people out in some way!
Cheers,
Alex
I have built a contact form using CakePHP on my site. The controller logic is as follows:
<?php
class ContactController extends AppController
{
var $helpers = array ('Html','Form');
var $components = array ('Email','RequestHandler');
var $name = 'Contact';
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow(array('*'));
}
function index()
{
if ($this->RequestHandler->isPost())
{
$this->Contact->set($this->data);
if ($this->Contact->validates())
{
$this->Email->to = '###';
$this->Email->subject = 'Contact message from ' . $this->data['Contact']['name'];
$this->Email->from = $this->data['Contact']['email'];
$this->Email->send($this->data['Contact']['message']);
$this->render('success');
}
}
}
}
?>
What I want to do is when a user submits the form is show another view file such as success.ctp but what happens is even though they have a new view they could refresh the page and send the data again and again. How do I stop this...
Can anyone help? Thanks
after you process their form data, redirect them to the same contact page (to avoid the refresh problem)
If you're not aware, you can setFlash to show a success message. But if you want to customize it the way you want, you can write a variable to Session to signal the view.
function index()
{
if ($this->RequestHandler->isPost())
{
$this->Contact->set($this->data);
if ($this->Contact->validates())
{
$this->Email->to = '###';
$this->Email->subject = 'Contact message from ' . $this->data['Contact']['name'];
$this->Email->from = $this->data['Contact']['email'];
$this->Email->send($this->data['Contact']['message']);
$this->Session->write('Contact.postmessage', true);
$this->redirect(array('action'=>'index'));
}
}
$this->Session->delete('Contact.postmessage');
}
And in the view:
if($this->Session->check('Contact.postmessage'){
// write out content of success.ctp
}else{
// write out form
}
You could try an approach of finding the count with the posted email less than five minutes ago or pop a Session flash message like 'Sorry you can only post every x minutes'
$this->Contact->find('count',array(
'conditions'=>array(
'email'=>$this->data['Contact'] ['email'],
'created <'=>date("Y-m-d H:i:s", strtotime('-5 minutes)));
To avoid sending message more then one time - place session value and check which view to render according to if that session value is placed.
e.g. on your email sending code add $this->Session->write('sent',1);
and when rendering: if ($this->Session->check('sent')) $this->render('common_view'); else $this->render('alternate_view');
And please make sure that page is redirected after email sending to itself via $this->redirect().
I cant seem to figure out how to create a flexible sidebar containing and login form (Zend_Form) and various module/controller specific links.
The most common solution seems to be using:
echo $this->action('login', 'authentication', 'default');
But apperently this isnt the 'best' way? I've read that this apprently triggers a dispatchloop and thereby take a performance hit?
I've thought about sing a View_Helper for the sidebar:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
$sidebar->append(new Form_Login);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
In my Form_Login i have action set to /auth/login which contains the following code:
public function loginAction()
{
$request = $this->getRequest();
if($request->isPost()) {
$form = new Form_Login();
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
If I provide the wrong username/password it renders indexAction which is currently empty. This is fine. It also renders my sidebar containing the loginForm as needed, but the form is empty (The user input is not displayed. Neither is no message that the form failed to validate).
The username-field in the form should display the input that the user provided before submitting. And a error message should be displayed.
Any help as to why this is not happing, is very much appriciated.
You are doing your form validation in a loginAction and you said you are currently posting to index action, is that a typo?
Besides that, you are creating two copies of the Form_Login. Once, in the action and once in view helper. If you validate on one instance in the action, you need to display that same instance of the form in the view helper. You could either move all the validation logic into the view helper or you could share the instance between the view helper and the action. I'm going to suggest the latter.
Check in your view helper if a form already exists in the registry. If it does, just use that instance. Otherwise you can create a new instance. Here's a rough example of what I mean:
class Zend_View_Helper_Sidebar extends Zend_View_Helper_Abstract
{
public function sidebar()
{
$sidebar = $this->view->placeholder('sidebar');
$sidebar->setPrefix('<div class="sidebar-element">')
->setSeparator('</div><div class="sidebar-element">')
->setPostfix('</div>');
if(Zend_Registry::isReigistered('loginForm')) {
$loginForm = Zend_Registry::get('loginForm');
} else {
$loginForm = new Form_Login();
}
$sidebar->append($loginForm);
$sidebar->append(new Model_Category->getList());
return $sidebar
}
}
public function loginAction()
{
$form = new Form_Login();
Zend_Registry::set('loginForm', $form);
$request = $this->getRequest();
if($request->isPost()) {
$data = $request->getPost();
if($form->isValid($data)) {
$username = $form->getValue('username');
$password = $form->getValue('password');
$users = new Model_DbTable_Users();
$authenticated = $users->login($username, $password);
if($authenticated) {
//Succes - show identity instead of loginForm
} else {
$this->view->loginForm = $form;
$this->render('/index');
}
}
}
}
Edit:
No, there is no self checking if an instance of a form already exists. You must do this yourself.
I'm pretty sure the suggested way is to use a view helper. As you said in your question, using the action view helper causes another dispatch loop which is bad for performance. I don't know what the verdict is on whether all logic should be kept in the view helper or not.