Joomla, php GET and redirecting - php

I have joomla 2.5 site, and I have
http://www.something.com/places?x=target
I would like to have URL like this:
http://www.something.com/places/target
How can I do this?
EDIT:
on .htaccess following works:
RewriteRule ^places/(.*)$ http://www.something.com/places?x=$1 [L,P,nc]
However it does not work with spaces ('/places/tar get' will only go to '/places?x=tar'). How can I fix that?
EDIT 2:
RewriteRule ^places/([^\ ])\ (.)$ http://www.something.com/places?x=$1\%20$2 [L,P,nc]
RewriteRule ^places/(.*)$ http://www.something.com/places?x=$1 [L,P,nc]
doest the trick. Thank you all!

If the places page belongs to a custom component (not a Joomla! built-in component), you will need to write or adjust the router.php file, in the component's directory.
It will need to contain something like:
function yourcomponentnameBuildRoute(&$query) {
$segments = array();
if (isset($query["x"])) {
$segments[] = $query["x"];
unset($query["x"]);
}
return $segments;
}
function yourcomponentnameParseRoute($segments) {
$vars = array();
$count = count($segments);
switch($segments[0]) {
case "target":
$vars["x"] = "target";
break;
}
return $vars;
}
UPDATE for your specific case:
Unfortunately there is no way to do this without a core hack.
So backup your *components/com_content/router.php* file, and then edit it as follows:
Replace the following code (around line 132):
if ($view == 'article') {
if ($advanced) {
list($tmp, $id) = explode(':', $query['id'], 2);
}
else {
$id = $query['id'];
}
$segments[] = $id;
}
unset($query['id']);
unset($query['catid']);
with this:
if ($view == 'article') {
if ($advanced) {
list($tmp, $id) = explode(':', $query['id'], 2);
}
else {
$id = $query['id'];
}
if(isset($query['x']) && $query['x']) {
$segments[] = $query['x'];
}
$segments[] = $id;
}
unset($query['x']);
unset($query['id']);
unset($query['catid']);
and this code (around line 212):
if (!isset($item)) {
$vars['view'] = $segments[0];
$vars['id'] = $segments[$count - 1];
return $vars;
}
// if there is only one segment, then it points to either an article or a category
// we test it first to see if it is a category. If the id and alias match a category
// then we assume it is a category. If they don't we assume it is an article
if ($count == 1) {
// we check to see if an alias is given. If not, we assume it is an article
if (strpos($segments[0], ':') === false) {
$vars['view'] = 'article';
$vars['id'] = (int)$segments[0];
return $vars;
}
with this:
if (!isset($item)) {
$vars['view'] = $segments[0];
$vars['id'] = $segments[$count - 1];
$vars['x'] = $count >= 2 ? $segments[$count - 2] : NULL;
return $vars;
}
// if there is only one segment, then it points to either an article or a category
// we test it first to see if it is a category. If the id and alias match a category
// then we assume it is a category. If they don't we assume it is an article
if ($count == 1 || ($count == 2 && (int) $segments[0] === 0)) {
// we check to see if an alias is given. If not, we assume it is an article
if (strpos($segments[0], ':') === false) {
$vars['view'] = 'article';
$vars['x'] = $count == 2 ? $segments[$count - 2] : NULL;
$vars['id'] = (int)$segments[$count - 1];
return $vars;
}
Then in your article's PHP code, you would use:
$target = JRequest::getVar("x");
I haven't tested it, so I'm not sure if it works. Let me know.

Related

How to remove part of path until a given directory is found?

I have paths that goes like this template:
`/dir1/dir2/dirN/dirNplus1/dirNplus2/`
And for an example to demonstrate this template:
`/var/www/sei/modules/module1/`
I would like to be able to have a function where I could input a full path and a specific directory and get in return only the right part of the path, removing the left part including the directory specified in the parameter.
In the example given, if I would use:
`function('/var/www/sei/modules/module1/', 'sei')`
Then I would like to get the result as:
`/modules/module1/`
Any ideas on how to achieve this?
As #ADyson suggested, I wrote this code below:
const DIRETORIO_SEI = 'sei';
private static $caminho;
public static function getCaminhoModulo($append = '') {
if (self::$caminho != null) {
return self::$caminho;
}
$diretorio = explode('/', realpath(__DIR__.'/../../../'));
$caminho = '';
$incluir = false;
for ($i = 0; $i < count($diretorio); $i++) {
if ($incluir) {
$caminho = $caminho . $diretorio[$i] . '/';
}
if ($diretorio[$i] == self::DIRETORIO_SEI) {
$incluir = true;
}
}
self::$caminho = $caminho;
return $caminho.$append;
}

Combination of where and where is not working

I have a problem code beneath this line does not work! How can I let this work? where ... orWhere orWhere does filter but cumulates the queries. where ... where does not provide any result. Can someone help me?
$artworks = Artwork::where('category_id', $category)
->where('style_id', $style)
->where('technic_id', $technic)
->where('orientation', $orientation)
->get();
Here is the full code:
if (request()->category_id) {
$category = request()->category_id;
} else {
$category = 0;
}
if (request()->style_id) {
$style = request()->style_id;
} else {
$style = 0;
}
if (request()->technic_id) {
$technic = request()->technic_id;
} else {
$technic = 0;
}
if (request()->orientation_id == 'vertical') {
$orientation = 'vertical';
} else if (request()->orientation_id == 'horizontal') {
$orientation = 'horizontal';
} else {
$orientation = 0;
}
$artists = Artist::get();
$artworks = Artwork::where('category_id', $category)
->where('style_id', $style)
->where('technic_id', $technic)
->where('orientation', $orientation)
->get();
return view('frontend.index', compact('artworks', 'artists'));
I think you want to use OR Condition and you are mistaking it with double where. Please look below to understand properly
If you want AND condition in your query then the double where are used but if you want OR condition then you have to use orWhere
Examples:
AND condition
Query::where(condition)->where(condition)->get();
OR Conditon
Query::where(condition)->orWhere(condition)->get();
If you expect all of your variables to be set
Your query variables category_id, style_id, orientation_id & technic_id are being defaulted to 0 if they are not true.
Your query is fine, but you may not have the data you think you do.
Run the following at the top of this function:
print_r($request->all());
exit;
If all of your variables are optional
very procedural, basic way to achieve this:
$artists = Artist::get();
$artworks = Artwork::where('id', '>', 0);
$category_id = request()->input('category_id');
if ($category_id != '') {
$artworks->where('category_id', request()->category_id);
}
$style_id = request()->input('style_id');
if ($style_id != '') {
$artworks->where('style_id', request()->style_id);
}
$technic_id = request()->input('technic_id');
if ($technic_id != '') {
$artworks->where('technic_id', request()->technic_id);
}
$orientation_id = request()->input('orientation_id');
if ($orientation_id != '') {
$artworks->where('orientation_id', request()->orientation_id);
}
$artworks->get();
return view('frontend.index', compact('artworks', 'artists'));

How to retrive multiple url parameter in php

I have 4 parameter in my URL. I retrieve the url parameter from my url that is given. With every parameter I'm changing the path to a directory and get different images.
My sample url look like this:
www.sample.com?cat=section1&language=de&prices=pl
The code is working but it's a spagheti code.
Is there a solution to make is less DRY ? How do I retrieve multiple url parameter ?
if(isset($_GET["cat"])) {
switch ($cat) {
case 'section1':
if(isset($_GET["language"])) {
$language = htmlspecialchars($_GET["language"]);
if($language == "de") {
if(isset($_GET["prices"])) {
$prices = htmlspecialchars($_GET["prices"]);
if($prices == "pl"){
$files=glob('pages/section1/dp/low/*.jpg');
}
else {
$files=glob('pages/section1/dn/low/*.jpg');
}
}
else {
$files=glob('pages/section1/dn/low/*.jpg');
}
}
elseif ($language == "en") {
if(isset($_GET["prices"])) {
$prices = htmlspecialchars($_GET["prices"]);
if($prices == "pl"){
$files=glob('pages/section1/ep/low/*.jpg');
}
else {
$files=glob('pages/section1/en/low/*.jpg');
}
}
else {
$files=glob('pages/section1/en/low/*.jpg');
}
}
elseif ($language == "cz") {
if(isset($_GET["prices"])) {
$prices = htmlspecialchars($_GET["prices"]);
if($prices == "pl"){
$files=glob('pages/section1/cp/low/*.jpg');
}
else {
$files=glob('pages/section1/cn/low/*.jpg');
}
}
else {
$files=glob('pages/section1/cn/low/*.jpg');
}
}
else {
$files=glob('pages/section1/cn/low/*.jpg');
}
}
else {
$files=glob('pages/section1/dn/low/*.jpg');
}
break;
case 'section2':
//the same like in section 1, path is .../section2/...
break;
case section3:
//the same like in section 1, path is .../section3/...
break;
default:
//the same like in section 1
break;
}
else {
//the same like in section 1
}
The path d=german, e=english, c=czech, p=prices, n=noprices
You could shorten/remove many if else statements with just doing the checks:
$lang_code = $language[0];
There you have your first letter, you can do the same with every GET parameter.
So you can use that as in:
$files=glob('pages/section1/'.$lang_code.'p/low/*.jpg');
You can do the same for everything else.
P.s.: don't forget to sanitze any user input i.e.:
$language=mysqli_real_escape_string($conn, $_GET['language']);
I'd probably do something like this:
<?php
$allowedCat = ['section1', 'section2'];
$allowedLanguage = ['pl', 'en', 'cz'];
$allowedPrice = ['pl', '??'];
$cat = (isset($_GET["cat"])) ? $_GET["cat"] : null;
$language = (isset($_GET["language"])) ? $_GET["language"] : null;
$prices = (isset($_GET["prices"])) ? $_GET["prices"] : null;
if (!in_array($cat, $allowedCat)) throw new \Exception('Invalid `cat`');
if (!in_array($language, $allowedLanguage)) throw new \Exception('Invalid `language` option.');
if (!in_array($prices, $allowedPrice)) throw new \Exception('Invalid `price` option.');
$someVar1 = ($prices === 'pl') ? 'p' : 'n';
$someVar2 = $language[0];
$files = glob("pages/{$cat}/{$someVar1}{$someVar2}/low/*.jpg");
Think that should be self explanatory. Translates one to one really. Was not certain on how the other price option was specified...

How To Get Twig Template Engine Header Tags in PHP Function

I am trying to extend a Pico navigation plugin to exclude items from the navigation tree where the page's utilizes Twig template engine header tags.
My question is how do I get specific header tags from the .md files in the below PHP function and filter them to be excluded in the navigation tree?
The plugin currently implements the ability to omit items (pages and folders) from the tree with the following settings in a config.php file:
// Exclude pages and/or folders from navigation header
$config['navigation']['hide_page'] = array('a Title', 'another Title');
$config['navigation']['hide_folder'] = array('a folder', 'another folder');
The current function in the plugs' file uses the above config.php as follows:
private function at_exclude($page) {
$exclude = $this->settings['navigation'];
$url = substr($page['url'], strlen($this->settings['base_url'])+1);
$url = (substr($url, -1) == '/') ? $url : $url.'/';
foreach ($exclude['hide_page'] as $p) {
$p = (substr($p, -1*strlen('index')) == 'index') ? substr($p, 0, -1*strlen('index')) : $p;
$p = (substr($p, -1) == '/') ? $p : $p.'/';
if ($url == $p) {
return true;
}
}
foreach ($exclude['hide_folder'] as $f) {
$f = (substr($f, -1) == '/') ? $f : $f.'/';
$is_index = ($f == '' || $f == '/') ? true : false;
if (substr($url, 0, strlen($f)) == $f || $is_index) {
return true;
}
}
return false;
}
I need to add the ability of omitting items (or pages) from the tree using the Twig header tags 'Type' and 'Status' like so in the .md files:
/*
Title: Post01 In Cat01
Description: This post01 in cat01
Date: 2013-10-28
Category:
Type: post // Options: page, post, event, hidden
Status: draft // Options: published, draft, review
Author: Me
Template:
*/
...
The MarkDown content . . .
So if a user wants to remove items tagged with "post" in the 'type' tag and/or "draft" from the 'draft' tag (see header above), they would then add the linked tags in the array below that I added into the config.php:
// Exclude taged items:
$config['navigation']['hide_status'] = array('draft', 'maybe some other status tag');
$config['navigation']['hide_type'] = array('post', 'etc');
I also added the following to the bottom of the at_exclude() function:
private function at_exclude($page) {
. . .
foreach ($exclude['hide_staus'] as $s) {
$s = $headers['status'];
if ($s == 'draft' || 'review') {
return true;
}
}
foreach ($exclude['hide_type'] as $t) {
$t = $headers['type'];
if ($t == 'post' || 'hidden') {
return true;
}
return true;
}
. . .
This is obviously not working for me (because my PHP knowledge is limited). Any help with what I am missing, doing wrong or how I can add this functionality will be greatly appreciated.
I dived into the (not so beautiful) Pico code and those are my findings.
First of all, Pico doesn't read every custom field you add to the content header.
Instead, it has an internal array of fields to parse. Luckily, an hook called before_read_file_meta is provided to modify the array.
In at_navigation.php we'll add:
/**
* Hook to add custom file meta to the array of fields that Pico will read
*/
public function before_read_file_meta(&$headers)
{
$headers['status'] = 'Status';
$headers['type'] = 'Type';
}
This will result in Pico reading the headers, but it won't add the fields to the page data yet. We need another hook, get_page_data. In the same file:
/**
* Hook to add the custom fields to the page data
*/
public function get_page_data(&$data, $page_meta)
{
$data['status'] = isset($page_meta['status']) ? $page_meta['status'] : '';
$data['type'] = isset($page_meta['type']) ? $page_meta['type'] : '';
}
Now, in the at_exclude function, we can add the new logic.
(Instead of cycling, We configure an array of status and types we want to exclude, and we'll check if there is a match with the current page status/type)
private function at_exclude($page)
{
[...]
if(in_array($page['status'], $exclude['status']))
{
return true;
}
if(in_array($page['type'], $exclude['type']))
{
return true;
};
return false;
}
Now let's customize our config.php (I standardized the configuration with the plugin standards):
$config['at_navigation']['exclude']['status'] = array('draft', 'review');
$config['at_navigation']['exclude']['type'] = array('post');
All done!
But if you are just starting out, I'd advise you to use a more mature and recent flat file cms. Unless you are stuck with PHP5.3
I decided to simplify the function to omit it from the config.php since it really isn't needed to be set by the end-user. By doing so, the at_exclude() function is much simpler and quicker on the back-end by omitting all the checks via other files:
at_exclude {
. . .
$pt = $page['type'];
$ps = $page['status'];
$home = ($pt == "home");
$post = ($pt == "post");
$event = ($pt == "event");
$hide = ($pt == "hide");
$draft = ($ps == "draft");
$review = ($ps == "review");
$type = $home || $post || $event || $hide;
$status = $draft || $review;
if ( $type || $status ) {
return true;
};
return false;
}
Obviously it needs some tidying up but you get the picture. Thnx

silverstripe, how to use the doPublish()

I am working with SilverStripe, and I am working on making a newspage.
I use the DataObjectAsPage Module( http://www.ssbits.com/tutorials/2012/dataobject-as-pages-the-module/ ), I got it working when I use the admin to publish newsitems.
Now I want to use the DataObjectManager Module instead of the admin module to manage my news items. But this is where the problem exists. Everything works fine in draft mode, I can make a new newsitem and it shows up in draft. But when I want to publish a newsitem, it won't show up in the live or published mode.
I'm using the following tables:
-Dataobjectaspage table,
-Dataobjectaspage_live table,
-NewsArticle table,
-NewsArticle_Live table
The Articles have been inserted while publishing in the Dataobjectaspage table and in the NewsArticle table... But not in the _Live tables...
Seems the doPublish() function hasn't been used while 'Publishing'.
So I'm trying the use the following:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
But when I use this, it gets an error:
here is this picture
It seems to be in a loop....
I've got the NewsArticle.php file where I use this function:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
This function calls the DataObjectAsPage.php file and uses this code:
function doPublish() {
if (!$this->canPublish()) return false;
$original = Versioned::get_one_by_stage("DataObjectAsPage", "Live", "\"DataObjectAsPage\".\"ID\" = $this->ID");
if(!$original) $original = new DataObjectAsPage();
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onBeforePublish', $original);
$this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID;
$this->write();
$this->publish("Stage", "Live");
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onAfterPublish', $original);
return true;
}
And then it goes to DataObject.php file and uses the write function ():
public function write($showDebug = false, $forceInsert = false, $forceWrite = false, $writeComponents = false) {
$firstWrite = false;
$this->brokenOnWrite = true;
$isNewRecord = false;
if(self::get_validation_enabled()) {
$valid = $this->validate();
if(!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING);
return false;
}
}
$this->onBeforeWrite();
if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);
}
// New record = everything has changed
if(($this->ID && is_numeric($this->ID)) && !$forceInsert) {
$dbCommand = 'update';
// Update the changed array with references to changed obj-fields
foreach($this->record as $k => $v) {
if(is_object($v) && method_exists($v, 'isChanged') && $v->isChanged()) {
$this->changed[$k] = true;
}
}
} else{
$dbCommand = 'insert';
$this->changed = array();
foreach($this->record as $k => $v) {
$this->changed[$k] = 2;
}
$firstWrite = true;
}
// No changes made
if($this->changed) {
foreach($this->getClassAncestry() as $ancestor) {
if(self::has_own_table($ancestor))
$ancestry[] = $ancestor;
}
// Look for some changes to make
if(!$forceInsert) unset($this->changed['ID']);
$hasChanges = false;
foreach($this->changed as $fieldName => $changed) {
if($changed) {
$hasChanges = true;
break;
}
}
if($hasChanges || $forceWrite || !$this->record['ID']) {
// New records have their insert into the base data table done first, so that they can pass the
// generated primary key on to the rest of the manipulation
$baseTable = $ancestry[0];
if((!isset($this->record['ID']) || !$this->record['ID']) && isset($ancestry[0])) {
DB::query("INSERT INTO \"{$baseTable}\" (\"Created\") VALUES (" . DB::getConn()->now() . ")");
$this->record['ID'] = DB::getGeneratedID($baseTable);
$this->changed['ID'] = 2;
$isNewRecord = true;
}
// Divvy up field saving into a number of database manipulations
$manipulation = array();
if(isset($ancestry) && is_array($ancestry)) {
foreach($ancestry as $idx => $class) {
$classSingleton = singleton($class);
foreach($this->record as $fieldName => $fieldValue) {
if(isset($this->changed[$fieldName]) && $this->changed[$fieldName] && $fieldType = $classSingleton->hasOwnTableDatabaseField($fieldName)) {
$fieldObj = $this->dbObject($fieldName);
if(!isset($manipulation[$class])) $manipulation[$class] = array();
// if database column doesn't correlate to a DBField instance...
if(!$fieldObj) {
$fieldObj = DBField::create('Varchar', $this->record[$fieldName], $fieldName);
}
// Both CompositeDBFields and regular fields need to be repopulated
$fieldObj->setValue($this->record[$fieldName], $this->record);
if($class != $baseTable || $fieldName!='ID')
$fieldObj->writeToManipulation($manipulation[$class]);
}
}
// Add the class name to the base object
if($idx == 0) {
$manipulation[$class]['fields']["LastEdited"] = "'".SS_Datetime::now()->Rfc2822()."'";
if($dbCommand == 'insert') {
$manipulation[$class]['fields']["Created"] = "'".SS_Datetime::now()->Rfc2822()."'";
//echo "<li>$this->class - " .get_class($this);
$manipulation[$class]['fields']["ClassName"] = "'$this->class'";
}
}
// In cases where there are no fields, this 'stub' will get picked up on
if(self::has_own_table($class)) {
$manipulation[$class]['command'] = $dbCommand;
$manipulation[$class]['id'] = $this->record['ID'];
} else {
unset($manipulation[$class]);
}
}
}
$this->extend('augmentWrite', $manipulation);
// New records have their insert into the base data table done first, so that they can pass the
// generated ID on to the rest of the manipulation
if(isset($isNewRecord) && $isNewRecord && isset($manipulation[$baseTable])) {
$manipulation[$baseTable]['command'] = 'update';
}
DB::manipulate($manipulation);
if(isset($isNewRecord) && $isNewRecord) {
DataObjectLog::addedObject($this);
} else {
DataObjectLog::changedObject($this);
}
$this->onAfterWrite();
$this->changed = null;
} elseif ( $showDebug ) {
echo "<b>Debug:</b> no changes for DataObject<br />";
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Clears the cache for this object so get_one returns the correct object.
$this->flushCache();
if(!isset($this->record['Created'])) {
$this->record['Created'] = SS_Datetime::now()->Rfc2822();
}
$this->record['LastEdited'] = SS_Datetime::now()->Rfc2822();
} else {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Write ComponentSets as necessary
if($writeComponents) {
$this->writeComponents(true);
}
return $this->record['ID'];
}
Look at the $this->onAfterWrite();
It probably goes to my own function on NewsArticle.php and there starts the loop! I'm not sure though, so i could need some help!!
Does anyone knows how to use the doPublish() function?
The reason that is happening is that in the DataObjectAsPage::publish() method, it is calling ->write() - line 11 of your 3rd code sample.
So what happens is it calls ->write(), at the end of ->write() your onAfterWrite() method is called, which calls publish(), which calls write() again.
If you remove the onAfterWrite() function that you've added, it should work as expected.
The doPublish() method on DataObjectAsPage will take care of publishing from Stage to Live for you.

Categories