I wrote my own mvc for php, and it seems to be working fine for me. But i am having trouble with getting the controller and the action:
http://www.example.com/controller/action
this works fine but as soon as there are small changes to the url my code breaks appart. for example:
http://www.example.com/controller? thi breaks, saying the controller? doesn't exist,
http://www.example.com/controller/action? thi breaks, saying the action? doesn't exist,
i can't figure out why it takes the ? in there and if any body know a more robust to get the correct controller and action i would love to know.
here is my code:
all the request are redirected to the same index.php page using .htaccess
class Framework {
....
private function setup() {
$uri = (isset($_SERVER['REQUEST_URI']))?$_SERVER['REQUEST_URI']: false;
$query = (isset($_SERVER['QUERY_STRING']))?$_SERVER['QUERY_STRING']: '';
$url = str_replace($query,'',$uri);
$arr = explode('/',$url);
array_shift($arr);
$this->controller =!empty($arr[0])?$arr[0]:'home';
$this->action = isset($arr[1]) && !empty($arr[1])?$arr[1]:'index';
}
}
$_SERVER['QUERY_STRING'] does not include the ? so when you do $url = str_replace($query,'',$uri);, you are not replacing the ?. It's therefore looking for a controller named controller?
There are various ways around this
replace with '?'.$query
Use explode('?', $url) to separate the query string from the URI
Get the $_SERVER['REQUEST_URL'] (which doesn't include the query string), rather than getting the whole thing and then splitting out yourself
Personally I would go with the last option, because wherever the code is already written for you, it tends to be quicker and more robust than anything you can write.
You should fix the problem by using an / before the ?
Related
A have a delete link which goes to another page, call a function, if the function is successful, then I sent the user back to the page where they clicked delete.
I use this to go back:
if ($booking->deleteBooking($_GET['id']))
{
header('Location: ' . $_SERVER['HTTP_REFERER']);
}
My link would look something like this:
/calendar.php?id=1&month=04&day=25&year=2014&t=11&v=true&f=true&reserved=true
Can I trim the link and remove &reserved=true when it's sent back?
Rather than performing string manipulations that could be prone to error, I suggest that you use PHP's URL functions to parse the HTTP_REFERER header and adjust it accordingly:
// parse the referrer
$referer = parse_url($_SERVER['HTTP_REFERER']);
// parse the querystring part
parse_str($referer['query'], $querystring);
// unset the reserved parameter (only if value is 'true'?)
if ($querystring['reserved'] === 'true') unset($querystring['reserved']);
// reconstruct the revised querystring
$referer['query'] = http_build_query($querystring);
// redirect to the adjusted URL
header('Location: ' . http_build_url($referer));
I suggest you avoid regex and str_replace because they will quickly fall flat when your URL structure changes.
I would put this in a class now because this is not the last time you'll need to do this (I just had to do it last week) or some other URL related thing. So, you should go ahead and encapsulate the functionality in one place now rather than later. You can always change the implementation later in one place if you find a better or more correct way to handle the task.
A few fairly important caveats regarding your script and possible solutions...
HTTP_REFERER can't really be relied upon. Browsers are not required to send it and many do not. You can get around that by sending the URL yourself in the query string (properly escaped) or possibly via a hidden form field. Otherwise, your redirect and script is going to fail in a lot of cases! See HTTP Referer not always being passed
You should always exit after sending a Location header if you want an immediate redirect... otherwise your script will keep chugging along happily doing stuff. (database queries, etc, etc) To that end, I would encapsulate your redirect code as well and have done so in my example solution.
http_build_url is not available by default in PHP. It's a pecl_http thing. Ultimately, it's not really required in this case and my example solution works without it.
Example Class Usage:
$referrer = 'http://example.com/calendar.php?id=1&month=04&day=25&year=2014&t=11&v=true&f=true&reserved=true';
$url = new URL($referrer);
$url->remove_param('reserved');
$url->redirect();
Class Code:
class URL
{
public $url = '';
function __construct ($url)
{
$this->url = $url;
}
function redirect ($response_code = 301)
{
header('Location: ' . $this->url, true, $response_code);
exit;
}
function remove_param ($param)
{
// Do nothing to URL without a Query String (hat tip #eggyal)
if (strpos($this->url, '?') === false) return $this->url;
// Split URL into base URL and Query String
list($url, $query) = explode('?', $this->url, 2);
// Parse Query String into array
parse_str($query, $params);
// Remove the parameter in question
unset($params[$param]);
// Rebuild Query String
$query = http_build_query($params);
// Piece URL back together and save to object
$this->url = $url . ($query ? "?$query" : '');
// Return URL in case developer really just wants an instant result
return $this->url;
}
}
Caveat: This will not retain any URL fragments (ie #fragment) In the case of HTTP_REFERER this should not matter as most browsers won't send that anyway. If that is functionality you decide you need, then it can easily be coded in at a later time.
Namespacing: For simplicity's sake, the code examples are not namespaced. However, for real life implementations, I suggest getting in the habit of using "namespace App;" at the top of any in-house class files and calling the class as such "new App\Class();" Especially if you're using or might ever use any third-party code in your project.
Performance Note: Don't worry about performance until it becomes a problem... your time is always the biggest bottleneck... not PHP. Value your time more than PHP's time! PHP will always be faster than spending your time copy pasta coding. Encapsulate your code (in classes or functions) and have time left to go outside and enjoy the weather now and in the future when you need to re-factor.
use preg_replace
preg_replace('/^&reserved=true/', '', $_SERVER['HTTP_REFERER']);
I want to show on my site an element depending on my site's url.
Currently i have the following code:
<?php
if(URL matches)
{
echo $something;
}
else
{
echo $otherthing;
}
?>
I wanted to know how do I get the URL on the if condition, because I need to have only one php archive to show on many diferent pages
EDIT: The solution provided by Rixhers Ajazi doesnt work for me, when i use ur code i get the same URI for both of my pages, so the if sentence always goes by the else side, is any way to get the exact string u can see on the browser to the PHP code
http://img339.imageshack.us/img339/5774/sinttulocbe.png
This is the place where it changes but, the URL i get on both sides is equal, im a little bit confused
To get the URL, use:
$url = http://$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
Use following syntax with URL
http://mysite.com/index.php?var1=val&var2=val
Now you can get the values of variables in your $_GET variable and use in if condition like
if($_GET['var1'])
You can do so by using the $_SERVER method like so :
$url = $_SERVER['PHP_SELF']; or $url = $_SERVER['SERVER_NAME'];
Read up on this more here
if($url == 'WHATEVER')
{
echo $something;
}
else
{
echo $otherthing;
}
?>
You can use different variables, e.g., $_SERVER["PHP_SELF"], or $_SERVER["REQUEST_URI"]. The first one contains the path after the server name and until a possible ? in the URL (the part with the GET parameters is excluded). The second one contains also the GET parameters. You can also retrieve the hostname used to connect to the server (in case you have a virtual host situation) using $_SERVER["HTTP_HOST"]. Therefore by concatenating all these you can reconstruct the full URL (if you really need it, maybe the script name is enough).
I saw some websites that (for example):
if you want to view your message box, then it is: example.com/file.php?action=pm and also if you want to send a message again the address and the file is the same, but the $_GET is different : example.com/file.php?action=sendpm
How does it work?
Is it just:
if ($_GET['action'] == "pm")
{
//lots of html code(divs, forms, etc) paste here for action=pm.
}
else
{
//lots of html code paste here for action=send
}
instead of having files : pm.php, send.php ... ?Or the mechanism is different?
I saw that SMF use this mechanism and also I saw something like this for facebook.com/?ref=something.
How does it work?
The easiest way is this:
$action = isset($_GET['action']) ? $_GET['action'] : 'default';
if(!in_array($action, array('list', 'of', 'allowed', 'pages')))
$action = 'default';
include($action . '.php');
Note that the validation step is incredibly important. Not properly validating the value leads to nasty security holes from users being able to read any files your script can access to users being able to execute arbitrary code.
Putting all code in a single file like you suggested in your question is a bad idea since it results in unreadable code. Especially when mixing PHP and HTML in the same file like your question suggested (tip: use a template engine!).
This is called routing and allows a single entry point to many functions within an single application.
Requests are taken, processed and routed to the correction function. This routing pattern fits well into the Model View Controller (MVC) pattern for organizing code.
Take a look at how the Zend Framework describes MVC and Routing:
http://framework.zend.com/manual/en/learning.quickstart.intro.html#learning.quickstart.intro.mvc
You can have a switch statement. For example
example.com/file.php?action=pm or example.com/file.php?action=sendpm
if (isset($_REQUEST['action'])) {
$param = $_REQUEST['action'];
switch($param) {
case "pm":
// Code goes here
break;
case "sendpm":
// Do something here
break;
default:
// handle the default case
break;
}
} else {
// Handle it here
}
Well there are even other ways to do it !!
Switch is one of the easiest way !!
My first contact with Ajax is happening right now, and I'm kind a confused. I've read many of questions asked, but I'm not able to read the answer, that is most likely here somewhere.
Situation is, I'm using OOP PHP approach, and all I do go through index.php with parameters. So I do not call any other .php file in form posts, button clicks..
I've created an HTML listbox (which I'd like to remove vertical scrollbar, but that's just a bonus to resolve), which feeds my categories in it.
Now, by clicking each category I'd like to call certain function that would then generate output for the other div.
function swapContent(){
$("#myPresentDiv").html('<img src="../../imgs/ajax-loader-big.gif"/>').show();
var cat = $('#listbox').val();
$("#action").change(alert(cat));
var url = "&s=".cat;
$.post(url, {contentVar: cat} ,function(data) {
$("#myPresentDiv").html(data).show();
});
}
So, my JQuery script picks up correct Category, I alert it to alert dialog, so I'm sure that's fine, and then with code as it is at the moment, I reload my whole page so I get, page in page in page in page...
I'm trying to figure out how to write JQ ajax call, that would return only the results, not the whole page.
can I put URL "index.php&s="cat, and then somehow tell to ajax "go through index, call function displayresults ($cat); ?
Hope everything I wrote make sense to you :)
Tnx.
The url's your ajax function call, must return only the page parts and not the whole html document.
If you have
$.post('ajax.php',data,function(d){
$('#responsediv').html(d).show();
});
The file ajax.php must only return the page parts,like
<div>This is the new content</div>
so you will not have page inside page.
If you look at the frameworks or cms out there, they basically have routes that map calls to your index.php function to methods of the controller.
This is a complex argument, you could try to start out reading this article
Yeah, that makes sense. Your question is basically: when you get a result of an AJAX op and insert it into your page, it inserts the whole layout again, rather than the template.
OK, so the solution is to make a call to a PHP script that is "unstyled" i.e. has no template data. Your PHP script should therefore just output a short HTML snippet rather than a page (you might have a 'header' and 'footer' that can be removed for this page). What action you need to take depends what you're using on the server side - framework? CMS? Custom PHP app?
I did the exact thing for a internal app quite some time ago....What happened was i was passing the class name, function name and the function parameters via ajax variables and reading the same in php at the backend and then call the appropriate function in the class with those paraeters.
The PHP code:
$option = trim($_GET['v']);
switch ( $option ) {
case 1:
$sid = trim($_GET['q']);
$page = trim($_GET['p']);
$method = trim($_GET['m']);
$class = new $page( $link );
echo $class->$method( $sid );
break;
case 2:
$page = trim($_GET['p']);
$method = trim($_GET['m']);
$class = new $page( $link );
echo $class->$method();
break;
default:
echo '';
break;
}
But this was an internal app, so there was no injection attacks, xss,xsrf,session hijack issues....things might differ for you
Hope this helps.
I think you are searching for a GENERAL strategy to handle ajax requests its upto you
for example Server Side Ajax
unless you are using a specific framework (CI , yii etc)
You might want to look into some frameworks, as they can make this for you infinitely easier to implement:
http://demo.atk4.com/demo.html?t=20
So I have a site with a dozen pages on it using Drupal as a CMS. Wanted to know how to set/append all href links on any page with a dynamic attribute?
so here is an example URL:
http://www.site.com/?q=node/4
and I wanted to append to the URL like so:
http://www.site.com/?q=node/4&attr=1234
Now I have a nav bar on the site and when I hover over the link I see the url but I need to append the &attr=1234 string to the end of it. The string is dynamic so it might change from time to time.
I was thinking jQuery would be a good choice to do this but does Drupal have any functionality as well?
Now I've seen a couple of posts on Stack:
Post 1
Post 2
Problem is I'm learning my way around Drupal and have minimal experience with jQuery but getting better with both. I see the jQuery can replace a HREF but looks like they hard coded the HREF, could jQuery find all HREF's on a page and append the string to it? Also does Drupal have this functionality and what would be the best approach?
Also need this to work for clean or standard URL format, so I think Apache would handle this I just wanted to make sure.
Thanks for any help
EDIT:
Looks like the general consensus is the Drupal should handle this type of request. Just looking for the best implementation. Simple function call would be best but I would like it to dynamically add it to all existing href's as I want this to be dynamic instead of hard coding any url/href calls. So I could add/remove pages on the fly without the need to reconfigure/recode anything.
Thanks for the great tips though
EDIT #2:
Okay maybe I'm asking the wring question. Here is what I need and why it's not working for me yet.
I need to pass a value in the url that changes some of the look and feel of the site. I need it to be passed on just about every href tag on the page but not on User logout or Admin pages.
I see in my template code where the nav links get generated, so I though I could pass my code in the attributes array as the second parm to the function, but that is setting the tag attributes and not the URL attributes.
Now I see the bottom nav links use this Drupal function: menu_navigation_links() in menu.inc but the top nav uses a custom function.
This function in the template.php script looks to be the one creating the links
function lplus($text, $path, $options = array()) {
global $language;
// Merge in defaults.
$options += array(
'attributes' => array(),
'html' => FALSE,
);
// Append active class.
if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
(empty($options['language']) || $options['language']->language == $language->language)) {
if (isset($options['attributes']['class'])) {
$options['attributes']['class'] .= ' active';
}
else {
$options['attributes']['class'] = 'active';
}
}
// Remove all HTML and PHP tags from a tooltip. For best performance, we act only
// if a quick strpos() pre-check gave a suspicion (because strip_tags() is expensive).
if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
$options['attributes']['title'] = strip_tags($options['attributes']['title']);
}
return '<a href="'. check_url(url($path, $options)) .'"'. drupal_attributes($options['attributes']) .'><b>'. ($options['html'] ? $text : check_plain($text)) .'</b></a>';
}
not sure how to incorporate what I need into this function.
So on the home page the ?q=node/ is missing and if I append the ampersand it throws an error.
http://www.site.com/&attr=1234 // throws error
But if I mod it to the correct format it works fine
http://www.site.com/?attr=1234
Assuming that when you mean pages, you mean the content type of pages (will work for any other content type as long as it's really content and not something in a block or view).
You can easily replace the contents of any node that is about to be viewed by running a str_replace or with a regular expression. For instance, using str_replace:
function module_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch($op) {
case "view":
$node->body = str_replace($expected_link, $desired_link);
break;
}
}
where you define desired link somewhere else. Not an optimal solution, but non-Javascript browsers (yes, they still exist!) can't get around the forced, desired URLs if you try to change it with Javascript.
I think doing it in Drupal/PHP would be cleaner. Check out Pathauto module: http://drupal.org/node/17345
There is a good discussion on a related topic here:
http://drupal.org/node/249864
This wouldn't use jquery (instead you would overwrite a function using PHP) but you could get the same result. This assumes, however, that you are working with menu links.
I think you should consider exploring PURL ( http://drupal.org/project/purl ) and some of the modules it works with e.g. spaces and context.
I don't suggest you use jQuery to do this. It's a better practice to do this server side in PHP (Drupal).
You can overwrite the links dynamically into your preprocess page function.
On your template.php file:
function *yourtheme*_preprocess_page(&$vars, $hook){
//You can do it for the region that you need
$vars['content'] = preg_replace('/<a href="(.*?)"/i', '<a href="$1&attr=1234"', $vars['content']);
}
Note:
I did not try it, its only a hint.
It will add your parameters to the outside links too.