PHP has a is_readable function which checks to see if the file is readable by the owner of the script. Is there a corresponding script to see if a file is readable by a specified user, for example
is_readable('Gavrilo Princip', 'black_hand.srj')
Not built in. I don't even think there is a command line utility to check if a certain user has read permissions to a file.
You can write your own function to do the checking though. Look into the fileperms(), fileowner(), filegroup(), and posix_getpwuid() functions.
Check this question
Check file permissions
PHP fileperms http://php.net/manual/en/function.fileperms.php
PHP stat http://www.php.net/manual/en/function.stat.php
The examples in there are for *nix systems. I don't know if it will operate the same on Windows hosts. With these you could get the GID and UID of the file.
I don't know if there is a PHP equivalent that would let you get the UID and/or GID of the particular system user. You may need to get that manually and search against those values. You can find the value typically in the /etc/passwd file
Thanks to the help of Chris and AndrewR I have come up with a, as of yet untested, solution. This solution is implemented in shell, and waits for input from standard in (designed to work with Apache RewriteMap). However, it can easily be modified to be called from either the command line or from a PHP script. It is a little bit more complicated than it has to be because we are piping the input of a function (getfacl) to a while loop. When we do this, it starts a new suprocess, so any variables declared or updated inside this loop (ie. result) will not be available to the outside world. Furthermore, I used getfacl as I can later expand it to also work with ACL permissions as well. Finally, for implementation reasons, I already know the owner of the file (user) before calling this script, however, if this is not the case, one can easily find this from the getfacl command.
#!/bin/bash
#USAGE: STDIN viewer:user:file
while read line
do
viewer=`echo $4 | cut -d ':' -f 1`
user=`echo $4 | cut -d ':' -f 2`
file=`echo $4 | cut -d ':' -f 3`
result=$(
getfacl $file 2>/dev/null | while read line
do
if [[ $user == $viewer ]] && [[ $line =~ ^user: ]]
then
permissions=`echo $line | cut -d ':' -f 3`
if [[ $permissions =~ r ]]
then
echo true
break
fi
elif [[ $user == $viewer ]] && [ $line =~ ^group: ]]
then
#NOTE: I take advantage of the fact that each user has one single group and that group has the same name as the user's name
permissions=`echo $line | cut -d ':' -f 3`
if [[ $permissions =~ r ]]
then
echo true
break
fi
elif [[ $line =~ ^other: ]]
then
permissions=`echo $line | cut -d ':' -f 3`
if [[ $permissions =~ r ]]
then
echo true
break
fi
fi
done
)
if [[ $result == "true" ]]
then
echo true
else
echo false
fi
done
Related
I wrote a bash script that needs to handle named arguments. I want to call it with
script.sh --dir /path/to/dir
The script is :
#/usr/bin/bash
while [ $# -gt 0 ]; do
echo "##$1##"
if [[ $1 == *"--"* ]]; then
param="${1/--/}"
declare $param="$2"
echo "\$1 contains -- : $1"
else
echo "\$1 does not contain -- : $1"
fi
shift
done
echo $dir
exit 0
When called on command line it works fine :
$ ./genCrt.sh --dir test
##--dir##
$1 contains -- : --dir
##test##
$1 does not contain -- : test
test
But when called from a php script, this way : $out = shell_exec("/path/to/script.sh --dir test");
I get this result :
##--dir##
$1 does not contain -- : --dir
##test##
$1 does not contain -- : test
I can't figure out why. I guess it might be an encoding problem but I don't really know how to check it...
[EDIT] It's not an encoding issue, I added this code
echo -n $1|hexdump -v
echo -n "--"|hexdump -v
and I get
##--dir##
0000000 2d2d 6964 0072
0000005
0000000 2d2d
0000002
So the dashes are encoded the same way : 2d
[/EDIT]
I'm using PHP 7.3.14-1~deb10u1, Apache/2.4.38 (Debian), Bash 5.0.3(1)-release.
Thanks
I'm setting up a script which takes some user data with the read command. Using this data I need to search the file range and then do some filtering.
Here's how it is,
Enter fromtime
read fromtime
Enter totime
read totime
Enter the ID
read id
Initially I SSH into a server and then there I have a directory, Records with path cd home/report/records here, I have:
REC_201901020345.gz (yyyymmddhhmm)
REC_201901120405.gz
REC_201903142543.gz
and so on.
These files have data along with the $id.
When the user inputs $fromtime and $totime it will be of format yyyymmddhh . Here, I need to go to that range of files and then grep for the $id and display. For example:
If $fromtime is 2019010103 and $totime is 2019031425. I need to go to only those specific range of files that is REC_201901020345.gz, REC_201901120405.gz, REC_201903142543.gz and perform the grep to find the id entered by the user.
I have tried this using an if condition but it doesn't seem to work. I am new to writing scripts like these. There might be mistakes when I have described everything here. Sorry for the same.
source config.sh
Enter fromtime
read fromtime
Enter totime
read totime
Enter the ID
read id
ssh $user#$ip
cd /home/report/records
# <-- need to know what to add here as described here, to navigate to the
# <-- specific range $fromtime-$totime. Then the command to find id will be
zfgrep $id *.gz
The result should be only the the data with the id's in the specified range of .gz files.
Try below command.
echo -e "$(ls -1 REC_????????????.gz 2>/dev/null)\nREC_${fromtime}##\nREC_${totime}##" | sort | sed -n "/##/,/##/p" | sed '1d;$d' | xargs zfgrep -a "$id"
Explanation:
'fromdate' and 'todate' along with a ## (say marker) is appended to the output of ls.
Sorted the input, resulting in desired file names enclosed with marker.
Both sed, prints only lines between marker.
Last one is the command, supposed to be executed for each file name.
You can omit pipes and all next commands, starting from end, and see how output is building.
To get the list of files within the given range (fromtime, totime), the following shell script may be used:
declare -i ta
for file in REC*.gz
do
ta=$(echo "${file}" | grep -oP 'REC_\K(.*)(?=[[:digit:]]{2}.gz)')
if [ "${ta}" ] ; then
if [ ${ta} -le ${totime} -a ${ta} -ge ${fromtime} ] ; then
echo -e "${file}"
fi
fi
done
I've come across a rather mystifying bug in bash, which I suspect has to do with the shell expansion rules.
Here's the story: at work, I've been tasked with documenting a massive internal website for coordinating company resources. Unfortunately, the code is quite ugly, as it has outgrew it's original purpose and "evolved" into the main resource for coordinating company efforts.
Most of the code is PHP. I wrote a few helper scripts to help me write the documentation; for example, one script extracts all the global php variables used in a php function.
At the center of all these scripts lies the "extract_function.sh" script. Basically, given a single php function name and a php source file, it extracts and outputs that php function.
Now here's the problem: somehow, as the script is extracting the function, it is basically inserting the output of ls / randomly within the output.
For example:
$ ./extract_function my_function my_php_file.php
function my_function {
// php code
/etc
/bin
/proc
...
// more php code
}
Even more confusingly, I've only gotten this to occur for one specific function from one specific file! Now, since the function is quite huge (500+ lines, I mean it when I say the code is ugly!), I haven't been able for the life of me to figure out what is causing this, or to come up with a simpler ad-hoc function to produce this behavior. Also, company policy prevents me from sharing the actual code.
However, here is my code:
#!/usr/bin/env bash
program_name=$(basename $0);
function_name=$1;
file_name=$2;
if [[ -z "$function_name" ]]; then
(>&2 echo "Usage: $program_name function_name [file]")
exit 1
fi
if [[ -z "$file_name" ]] || [ "$file_name" = "-" ]; then
file_name="/dev/stdin";
fi
php_lexer_file=$(mktemp)
trap "rm -f $php_lexer_file" EXIT
read -r -d '' php_lexer_text << 'EOF'
<?php
$file = file_get_contents("php://stdin");
$tokens = token_get_all($file);
foreach ($tokens as $token)
if ($token === '{')
echo PHP_EOL, "PHP_BRACKET_OPEN", PHP_EOL;
else if ($token == '}')
echo PHP_EOL, "PHP_BRACKET_CLOSE", PHP_EOL;
else if (is_array($token))
echo $token[1];
else
echo $token;
?>
EOF
echo "$php_lexer_text" > $php_lexer_file;
# Get all output from beginning of function declaration
extracted_function_start=$(sed -n -e "/function $function_name(/,$ p" < $file_name);
# Prepend <?php so that php will parse the file as php
extracted_function_file=$(mktemp)
trap "rm -f $extracted_function_file" EXIT
echo '<?php' > $extracted_function_file;
echo "$extracted_function_start" >> $extracted_function_file;
tokens=$(php $php_lexer_file < $extracted_function_file);
# I've checked, and at this point $tokens does not contain "/bin", "/lib", etc...
IFS=$'\n';
open_count=0;
close_count=0;
for token in $tokens; do # But here the output of "ls /" magically appears in $tokens!
if [ $token = "PHP_BRACKET_OPEN" ]; then
open_count=$((open_count+1))
token='{';
elif [ $token == "PHP_BRACKET_CLOSE" ] ; then
close_count=$((close_count+1))
token='}';
fi
echo $token;
if [ $open_count -ne 0 ] && [ $open_count -eq $close_count ]; then
break;
fi
done
Yes, I know that I shouldn't be using bash to manipulate php code, but I basically have two questions:
1) Why is bash doing this?
2) And, how can I fix it?
One of the tokens in $tokens is a * (or a glob pattern which can match several files). If you cannot arrange for the token list to not contain shell metacharacters, you will need to jump through some hoops to avoid expansion. One possible technique is to use read -ra to read the tokens into an array, which will make it easier to quote them.
I have a semi-lengthy shell command that I need to execute from within php. I feel like I have everything properly escaped, however it is not working properly when executed from php's exec() function. When I run the command with exec() it exits without error, but does not run properly.
I am comparing a list file that has email addresses with additional pipe delimited information against a text file containing the md5 version of email addresses to suppress from the original list.
Here is the bash command:
while read line ; do email=`echo "$line" | cut -d '|' -f1` ; if [ $(E=`echo -en "$email" | md5sum | awk '{print $1}'`; grep $E /path/to/suppressions | head -1 ;) ] ; then continue ; else echo $line ; fi done < /path/to/emails
/path/to/suppressions is a text file, containing the md5 version of an email address to suppress (it contains the md5 for "emailtosuppress#domain.com":
edb5feb3be7d0a4e1e250ccdf0c04ace
/path/to/emails is a text file containing a list of email addresses with some other delimeted information:
emailtokeep#domain.com|1000|1
emailtosuppress#domain.com|1000|1
When the command is executed in bash, the output is simply the email address that does NOT exist in the suppression list, and it works flawless:
emailtokeep#domain.com|1000|1
The trouble I am having is when I execute this same command with exec() in php, it outputs all the lines from the "emails" file, without suppressing any matches from the suppression file.
$supCommand = 'while read line ; do email=`echo "$line" | cut -d \'|\' -f1` ; if [ $(E=`echo -en "$email" | md5sum | awk \'{print $1}\'`; grep $E /path/to/suppressions | head -1 ;) ] ; then continue ; else echo $line ; fi done < /path/to/emails' ;
exec($supCommand, $supStatus) ;
print_r($supStatus) ;
I enclosed the command in single quotes, and escaped the four instances of single quotes within the command. If anyone has any ideas I would be extremely GRATEFUL.
Thanks in advance :)
This seems to work:
<?php
$bash = '
mapfile -t md5sums < suppressions
function md5 { printf "%s" "$1" | md5sum | cut -f1 -d" "; }
while IFS="|" read -r email b c; do
this_md5=$(md5 "$email")
for suppress in "${md5sums[#]}"; do
[[ $this_md5 == $suppress ]] && continue 2
done
echo "$email|$b|$c"
done < emails
';
$cmd = "bash -c '$bash'";
$keep = passthru($cmd);
print($keep);
?>
I need to run
eval "php /srv/www/scripts/mage/install-invoke-app.php"
which it finds the file, but end up with
Which is messing up on the <?php right off. Why? How is that fixed? Googling so far has not produced the right answer.
update
Here is the script in short, it's a function, then I pass a call back .. there is tons stripped out so just the area only.
in the including base.sh script
cd /srv/www/
. scripts/install-functions.sh
#tons of other stuff
cd /srv/www/
. scripts/mage-install.sh
in install-functions.sh
install_repo(){
if [ $2 ]
then
echo "just 1"
git clone $1 -q
else
echo "just 1 and 2"
git clone $1 $2 -q
fi
success=$?
if [[ $success -eq 0 ]];
then
echo "Repository successfully cloned."
echo "cleaning"
cd $r/
rm -rf LICENSE.txt STATUS.txt README.md RELEASE_NOTES.txt modman
cd ../
cp -af $r/* .
rm -rf $r/
if [ -z "$3" ]
then
echo "no callback"
else
eval $3
fi
else
echo "Something went wrong!"
fi
sleep 1 # slow it down to insure that we have the items put in place.
}
#declare -A list = ( [repo]=gitUser )
install_repolist(){
gitRepos=$1
for r in "${!gitRepos[#]}" #loop with key as the var
do
giturl="git://github.com/${gitRepos[$r]}/$r.git"
echo "Adding $r From $giturl"
if [ -z "$r" ];
then
echo
else
install_repo $giturl $2 $3
fi
echo
done
return 1
}
In the scripts/mage-install.sh
declare -A gitRepos
#[repo]=gitUser
gitRepos=(
[wsu_admin_base]=jeremyBass
[wsu_base_theme]=jeremyBass
[Storeutilities]=jeremyBass
[StructuredData]=jeremyBass
)
cd /srv/www/mage/
install_repolist $gitRepos 0 "php /srv/www/scripts/mage/install-invoke-app.php"
unset gitRepos #unset and re-declare to clear associative arrays
declare -A gitRepos
And that is the basic loop here.. I need to call back to a function, but that install_repolist is used in other areas too so I can't hard code it. If there is a better way then eval, cool
There are still some parts of your script that I don't understand, or not sure it does really work, but about your question, I think your callback could only work if you place it on a function like:
function mycallback {
php /srv/www/scripts/mage/install-invoke-app.php
}
And call your install_repolist function as
install_repolist $gitRepos 0 mycallback
That should make your php command call with the file argument work but there is one thing: I don't think values of gitRepos could actually be passed like that.
Most parts of your code has variables that actually needed to be quoted around double quotes "". One problem with it is that your php command would just end up in the final place where it is executed as one single argument php and no longer with the file due to word splitting.