I'm planning to obscure link urls with the following way. It stores urls in an array and then if it detects the parameter in the $_GET array, it redirects to the saved url.
<?
/* Plugin Name: Sample Link Cloak */
add_action('admin_menu', 'sample_link_cloak');
function sample_link_cloak() {
add_options_page(
'Sample Link Cloak',
'Sample Link Cloak',
'manage_options',
'sample_link_cloak',
'sample_link_cloak_admin');
}
function sample_link_cloak_admin() {
?>
<div class="wrap">
<?php
$links = '<p>google.com</p>' . PHP_EOL
. '<p>wordpress.org</p>' . PHP_EOL
. '<p>stackoverflow.com</p>' . PHP_EOL;
$doc = new DOMDocument();
#$doc->loadHTML($links);
$array_urls = array();
foreach ($doc->getElementsByTagName('a') as $node) {
$url = $node->getAttribute('href');
$hash = md5($url);
$array_urls[$hash] = $url;
$url = site_url('?urlcloak=' . $hash);
$node->setAttribute('href', $url);
}
echo $doc->saveXML();
update_option('sample_urlcloak', $array_urls);
?>
</div>
<?php
}
add_action('init', 'cloakurls');
function cloakurls() {
if (isset($_GET['urlcloak'])) {
$array_urls = get_option('sample_urlcloak');
wp_redirect($array_urls[$_GET['urlcloak']]);
exit;
}
}
There is a problem I can predict with this method. The number of links increases day by day so the stored data have to be deleted when they reach to some extent. But if the visitor saves the web page on the local drive and read the contents later on and click the link, at this point if the server does not store the url, it won't redirect.
I think it is pretty much the same issue described here. Looking for more efficient way to serve numerous link redirects? but for a distributed plugin, is it realistic/practical to edit the .htaccess file? I guess not all users have the right access to modify .htaccess. I'm not sure.
I'm wondering if somebody can direct me to the right direction.
It depends on your application. Usually you can do what the other SO post describes, but if it really is random; or you don't have control over the redirected site - use a database. It's function is to quickly find what you are looking for on a hard drive.
Now to wonder a bit further than your current approach - what about two-way obfuscation? If it's just obfuscation (not security) use such an algorithm that you could both encrypt and decrypt the url. That way you wouldn't need to store any data.
Related
I have a Book Now button on each page of my website. I would like to know which button is selected and don't really want to add 25+ blocks to the site to add the class manually. I can use Google Analytics if I can make the button unique (add an additional class based on the page URL). But I'm not a coder although I'm familiar with both PHP and jQuery.
Hye Michael, after reading your question i have tested your scenario on my local test drupal site. And it's really easy to achieve it. Here is a piece of PHP code you need to put into your block you created.
<?php
$url = current_path();
$class_from_url = explode("/", $url);
echo "<a href=[link_to_whatever] class='". $class_from_url[0] ."'>[Link Title]</a>";
?>
Make sure your "PHP filter" module is enabled which will allow you to select PHP code from "Text formats" under the block body.
For Drupal 7, the best way to accomplish your goal would be to copy the theme_button() function to your theme's template.php file and add some custom code to check the URL and add the class.
YOURTHEME_button($vars) {
$element = $variables ['element'];
$element ['#attributes']['type'] = 'submit';
element_set_attributes($element, array('id', 'name', 'value'));
$element ['#attributes']['class'][] = 'form-' . $element ['#button_type'];
if (!empty($element ['#attributes']['disabled'])) {
$element ['#attributes']['class'][] = 'form-button-disabled';
}
// Check URL to determine what button class to add
$button_class = null;
$current_path = base_path() . request_path();
switch ($current_path) {
'/form1':
$button_class = 'button-for-form1';
break;
'/form2':
$button_class = 'button-for-form2';
break;
}
if ($button_class !== null) {
$element ['#attributes']['class'][] = $button_class;
}
return '<input' . drupal_attributes($element ['#attributes']) . ' />';
}
Note that this method will add the class only for URLs that you explicitly specify, and it ignores any user-supplied parameters that might be included as part of the URL.
we are running a Magento 1.4.2.0 Webshop with google analytics.
As we all know google attaches a querystring called the "gclid-Param" to the url.
The customer clicks the following url: http://www.myshop.com/bathrooms/showersbaths.html?glicd=somevalue
The category "bathrooms" was renamed inside magento, so magento automatically created a redirect from the old categoryname to the new name "bathroom furniture".
So now we have the problem, that magento cuts off the querystring with the glic-param when it rewrites and redirects the url.
Does anybody know how to prevent this or in which core-Module we have to modify the building of the new url?
best regards
Markus
In 1.9.1.0 this problem could be solved through patching in another class Mage_Core_Model_Url_Rewrite_Request/function _processRedirectOptions().
Just add after code
$targetUrl = $this->_request->getBaseUrl() . '/' . $this->_rewrite->getTargetPath();
$storeCode = $this->_app->getStore()->getCode();
if (Mage::getStoreConfig('web/url/use_store') && !empty($storeCode)) {
$targetUrl = $this->_request->getBaseUrl() . '/' . $storeCode . '/' . $this->_rewrite->getTargetPath();
}
if ($this->_rewrite->hasOption('R') || $isPermanentRedirectOption) {
the following
$queryString = $this->_getQueryString();
if ($queryString) {
$targetUrl .= '?'.$queryString;
}
and make sure 'if' statement keep closed with
$this->_sendRedirectHeaders($targetUrl, $isPermanentRedirectOption);
}
I'm sure it's fairly enough because of you don't need to transfer query string for external redirects.
Happy coding
After some more deep research inside the chaos of magento we found the solution to solve our Problem.
In the Url-Model of the Mage_Core exists a class rewrite.php.
We created a custom model and overwrited the rewrite.php.
Inside of the function rewrite(), we added the following piece(marked as comments) of code:
//$url_params = false;
//if ($url_params = $_SERVER['QUERY_STRING'])
//$url_params = "?".$url_params;
if ($external === 'http:/' || $external === 'https:')
{
if ($isPermanentRedirectOption)
{
header('HTTP/1.1 301 Moved Permanently');
}
header("Location: ".$this->getTargetPath() //.$url_params);
exit;
}
else
{
$targetUrl = $request->getBaseUrl(). '/' . $this->getTargetPath();
}
$isRedirectOption = $this->hasOption('R');
if ($isRedirectOption || $isPermanentRedirectOption)
{
if (Mage::getStoreConfig('web/url/use_store') && $storeCode =
Mage::app()->getStore()->getCode())
{
$targetUrl = $request->getBaseUrl(). '/' . $storeCode . '/'
.$this->getTargetPath();
}
if ($isPermanentRedirectOption)
{
header('HTTP/1.1 301 Moved Permanently');
}
header('Location: '.$targetUrl //.$url_params);
exit;
}
So i hope our solution helps others, who are facing the same problem.
Best regards
Markus
I am running 2.1.0 community edition right now and am having the same issue. I tried finding the files above, but they seem to be specific to the 1.X versions of Magento (at least the implementation within the files). I've found a work around for this, but I hate hate hate the way I am doing it. That being said, I am not noticing any performance problems with the site and I didn't have to modify any Magento core files. So... here is what I did;
I already had a directory under the Magento root directory that I use to host static content.
I created two files in this directory: startscripts.js (which I use to load any custom scripts within the head element) and endscripts.js (which I use to load any custom scripts right before the end of the body element).
In the administration page, go to content, configuration, and edit your site.
In the html head section add
<script src="/[staticDirectoryYouCreate]/startscripts.js" type="text/javascript"></script>
to the scripts and stylesheets section
In the footer section on this same page, add
<script src="/[staticDirectoryYouCreate]/endscripts.js" type="text/javascript" defer></script>
to the Miscellaneous HTML section
Here is the script that I created in the endscripts.js file to append the gclid to links on the page:
try
{
var urlParameters = /gclid=([^&]+)/.exec(document.location.toString());
if(urlParameters)
{
if(urlParameters[1])
{
var siteLinks = document.getElementsByTagName("a");
for(var currentLink=0;currentLink < siteLinks.length;currentLink++)
{
if(siteLinks[currentLink].href.toString().indexOf("gclid") < 0)
{
if(siteLinks[currentLink].href.toString().indexOf("?") < 0)
{
siteLinks[currentLink].href=siteLinks[currentLink].href+"?gclid="+urlParameters[1];
}
else
{
siteLinks[currentLink].href=siteLinks[currentLink].href+"&gclid="+urlParameters[1];
}
}
}
}
}
}
catch(e){}
For this particular fix, you don't have to add the startscripts.js file, but the Google tag assistant was complaining that the Google Analytics snippet was outside of the head element, so I disabled the Magento Google Analytics implementation and put the snippet in the startscripts.js file.
I'll be curious to hear folks opinions on solving the problem this way.
I know the way to get all user media in instagram api with pagination. And we must request again with pagination url provided to get next photos.
I just wonder if i can save all of json api response include with next photos in pagination to one flat file for caching. The purpose is i can call all photos value from one file only, e.g: cache.json.
Is there a way to realize that in PHP Code if possible? Like using file_get and file_put function. Any help is appreciated so much :)
Here's my code, but need a tweak to fix it. Im using this wrapper https://github.com/cosenary/Instagram-PHP-API
require 'instagram.class.php';
$cache = './cache.json';
$instagram = new Instagram($accessToken);
$instagram->setAccessToken($accessToken);
$response = $instagram->getUserMedia($userID,$settings['count']);
do {
if($response){
file_put_contents($cache,json_encode($response)); //Save as json
}
} while ($response = $instagram->pagination($response));
echo 'finish';
With this code i getting the last pagination only. It seems the code overwrite the cache.json file, not adding.
Maybe you can suggest me how to fix it become adding, not overwriting.
-- Edit --
My code now working but not perfect, maybe you can try and fix it.
<?php
include('conf.php');
require 'instagram.class.php';
$cache = './cache_coba.json';
$instagram = new Instagram($accessToken);
$instagram->setAccessToken($accessToken);
$response = $instagram->getUserMedia($userID,$settings['count']);
while ($response = $instagram->pagination($response)) {
if($response){
$opn = file_get_contents($cache);
$opn .= json_encode($response);
file_put_contents($cache, $opn);
}
}
echo 'finish';
?>
Hi i wont to make something like that.
http:// example.com/ - Main Controller
http:// example.com/rules/ - Main Controller where content get from database, but if not exist
return 404 page. (It's ok, isn't problem.)
But if i have subfolder in application/controlles/rules/
I want to redirect it to Main Contorller at Rules folder.
This follow code can solve problem, but i don't know how it right realise.
At routes.php:
$route['default_controller'] = "main";
$route['404_override'] = '';
$dirtest = $route['(:any)'];
if (is_dir(APPPATH.'controllers/'.$dirtest)) {
$route['(:any)'] = $dirtest.'/$1';
} else {
$route['(:any)'] = 'main/index/$1';
}
Ok, what I have:
controllers/main.php
class Main extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('main_model');
}
public function index($method = null)
{
if (is_dir(APPPATH.'controllers/'.$method)) {
// Need re-rout to the application/controllers/$method/
} else {
if ($query = $this->main_model->get_content($method)) {
$data['content'] = $query[0]->text;
// it shows at views/main.php
} else {
show_404($method);
}
}
$data['main_content'] = 'main';
$this->load->view('includes/template', $data);
}
}
Updated Again (routes.php):
So, seem's like what i search (work example):
$route['default_controller'] = "main";
$route['404_override'] = '';
$subfolders = glob(APPPATH.'controllers/*', GLOB_ONLYDIR);
foreach ($subfolders as $folder) {
$folder = preg_replace('/application\/controllers\//', '', $folder);
$route[$folder] = $folder.'/main/index/';
$route[$folder.'/(:any)'] = $folder.'/main/$1';
}
$route['(:any)'] = 'main/index/$1';
But, in perfectly need some like this:
http:// example.com/1/2/3/4/5/6/...
Folder "controllers" has subfolder "1"?
YES: Folder "1" has subfolder "2"?
NO: Folder "1" has controller "2.php"?
NO: Controller "controllers/1/main.php" has function "2"?
YES: redirect to http:// example.com/1/2/ - where 3,4,5 - parameters..
It is realy nice, when you have structure like:
http://example.com/blog/ - recent blog's posts
http://example.com/blog/2007/ - recent from 2007 year blog's posts
http://example.com/blog/2007/06/ - same with month number
http://example.com/blog/2007/06/29/ - same with day number
http://example.com/blog/web-design/ - recent blog's post's about web design
http://example.com/blog/web-design/2007/ - blog' posts about web design from 2007 years.
http://example.com/blog/current-post-title/ - current post
Same interesting i find http://codeigniter.com/forums/viewthread/97024/#490613
I didn't thoroughly read your question, but this immediately caught my attention:
if (is_dir($path . '/' . $folder)) {
echo "$route['$folder/(:any)'] = '$folder/index/$1';"; //<---- why echo ???
}
Honestly I'm not sure why this didn't cause serious issues for you in addition to not working.
You don't want to echo the route here, that will just try to print the string to screen, it's not even interpreted as PHP this way. There are also some issues with quotes that need to be remedied so the variables can be read as variables, not strings. Try this instead:
if (is_dir($path . '/' . $folder)) {
$route[$folder.'/(:any)'] = $folder.'/index/$1';
}
Aside: I'd like to offer some additional resources that are not directly related to your problem, but should help you nonetheless with a solution:
Preferred way to remap calls to controllers: http://codeigniter.com/user_guide/general/controllers.html#remapping
Easier way to scan directories: http://php.net/manual/en/function.glob.php
It's hard to say why the registering of your routes fails. From your code I can see that you're not registering the routes (you just echo them), additionally I see that the usage of variables in strings are used inconsistently. Probably you mixed this a bit, the codeigniter documentation about routes is not precise on it either (in some minor points, their code examples are not really syntactically correct, but overall it's good).
I suggest you first move the logic to register your dynamic routes into a function of it's own. This will keep things a bit more modular and you can more easily change things and you don't pollute the global namespace with variables.
Based on this, I've refactored your code a bit. It does not mean that this works (not tested), however it might make things more clear when you read it:
function register_dynamic_routes($path, array &$route)
{
$nodes = scandir($path);
if (false === $nodes)
{
throw new InvalidArgumentException(sprintf('Path parameter invalid. scandir("$path") failed.', $path));
}
foreach ($nodes as $node)
{
if ($node === '.' or $node === '..')
continue
;
if (!is_dir("{$path}/{$node}")
continue
;
$routeDef = "{$folder}/(:any)";
$routeResolve = "{$folder}/index/\$1";
$route[$routeDef] = $routeResolve;
# FIXME debug output
echo "\$route['{$routeDef}'] = '{$routeResolve}';";
}
}
$path = APPPATH.'controllers/';
register_dynamic_routes($path, $route);
$route['(:any)'] = 'main/index/$1';
Next to this you probably might not want to shift everything onto the index action, but a dynamic action instead. Furthermore, you might want to have a base controller that is delegating everything into the sub-controllers instead of adding the routes per controller. But that's up to you. The example above is based on the directory approach you outlined in your question.
Edit: Additional information is available in the Controllers section next to the URI Routing section
All this seems kind of complicated.
Plus, if you have hundreds (or thousands or more?) of possible routes in a database you may not want to load all of them into the "$routes" array every time any page loads in your application.
Instead, why not just do this?
last line of routes.php:
$route['404_override'] = 'vanity';
Controller file: Vanity.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Vanity extends MY_Controller {
/**
* Vanity Page controller.
*
*/
public function __construct() {
parent::__construct();
}
public function index()
{
$url = $_SERVER['PHP_SELF'];
$url = str_replace("/index.php/", "", $url);
// you could check here if $url is valid. If not, then load 404 via:
//
// show_404();
//
// or, if it is valid then load the appropriate view, redirect, or
// whatever else it is you needed to do!
echo "Hello from page " . $url;
exit;
}
}
?>
After reading this thread: How to force browser to reload cached CSS/JS files?
I would like to know if there is any built-in function or easy way in Symfony that automatically forces a reload by appending a random querystring or timestamp to the link when it has discovered that javascript / css file has been modified. (Normally, people use the use_javascript function to generate the <script> tag)
There is no built-in mechanism, but a little creativity means you can do this just about anywhere in your code, from view.yml to layout.php to each individual action.
The view.yml method is easy enough:
apps/frontend/config/view.yml:
stylesheets: [main?v=<?php echo time() ?>, reset?v=<?php echo time() ?>, layout?v=<?php echo time() ?>]
Although I think this is a little too active, and I tend to use either the SVN revision or a overall project version number:
stylesheets: [main?v=<?php echo sfConfig('app_project_version') ?>, reset?v=<?php echo sfConfig('app_project_version') ?>, layout?v=<?php echo sfConfig('app_project_version') ?>]
where app_project_version is set in apps/frontend/config/app.yml. Methods for layout.php and actionSuccess.php should be easy enough from here:
<?php use_stylesheet('blah?v='.sfConfig::get('app_project_version')); ?>
instead of setting a version for each stylesheet you include, it is better to have it done automatically for all included stylesheets, no matter if you use view.yml or use_stylesheet() method. You need to implement this helper method and
include the helper in your applications settings.yml, so that it becomes available to alle your actions.
`
function include_versioned_stylesheets()
{
$response = sfContext::getInstance()->getResponse();
sfConfig::set('symfony.asset.stylesheets_included', true);
$html = '';
foreach ($response->getStylesheets() as $file => $options) {
$filepath = sfConfig::get('sf_web_dir') . '/' . stylesheet_path($file);
if(file_exists($filepath)) {
$file .= '?v=' . filectime($filepath);
}
$html .= stylesheet_tag($file, $options);
}
echo $html;
}
`
in your layout.php call this inside your header area. make sure there is no further call to include_stylesheets(), as this is an extended version to it.
same can be done with include_javascripts.