php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #841 basename() & dirname() do not parse path correctly
Submitted: 1998-10-09 18:34 UTC Modified: 1998-12-21 14:06 UTC
From: inlan at flash dot net Assigned:
Status: Closed Package: Misbehaving function
PHP Version: 3.0.5 OS: Win95
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: inlan at flash dot net
New email:
PHP Version: OS:

 

 [1998-10-09 18:34 UTC] inlan at flash dot net
I was trying to use basename() & dirname() to break up a parse_url()["path"] into the directory & filename.  It seems these functions simply break at the last '/'.

Here's what they return:
PATH       dirname()  basename()
adir/afile  adir       afile <<this one is ok
adir/       adir       adir/
/adir/     (nothing)   adir
afile       afile      afile
/          (nothing)    /

This would be nice (and seems correct to me):
PATH       dirname()  basename()
adir/afile  adir       afile
adir/       adir      (nothing)
/adir/      /adir     (nothing)
afile      (nothing)   afile
/afile       /         afile
/            /        (nothing)

I'm using phpweb distribution...
PHP Version 3.0.5-dev
System: Windows 95/98 4.0
Build Date: Oct 3 1998

The ChangeLog says, "Added basename and dirname functions similar to sh counterparts."  I don't know if these are the desired results.

If I'm going to gripe...
Below is patched source code for what I think is supposed to happen.  If the results I'm getting are the desired results, I'd love to still have the functions below (with any suitable name).  The existing ones don't seem too
useful--which could be a lack of understanding on my part.

I'm not set up to compile PHP3, but I believe the coding is correct.

Rich Clingman
inlan@flash.net

###  patches to basename() & dirname() in functions/string.c
###  Rich Clingman inlan@flash.net 06OCT98
###  manual "patch" notation: < take out    > put in

void php3_basename(INTERNAL_FUNCTION_PARAMETERS)
{
pval *str;
char *ret, *c;
TLS_VARS;

if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str)) {
  WRONG_PARAM_COUNT;
}
convert_to_string(str);

### As the function is rewritten below,
### we do not modify the string
### (only return a value).
### Can we use 'str' directly?
### If so, dump this line
### and change 'ret' to 'str' in added lines.

ret = estrdup(str->value.str.val);

< c = ret + str->value.str.len -1;
<  while (*c == '/'
<  #ifdef MSVC5
<       || *c == '\\'
<  #endif
<    )
<    c--;
<   *(c + 1) = '\0';
< if ((c = strrchr(ret, '/'))
<#ifdef MSVC5
<  || (c = strrchr(ret, '\\'))
<#endif
<  ) {
<  RETVAL_STRING(c + 1,1);
< } else {
<    RETVAL_STRING(str->value.str.val,1);
< }

> // if no slash, then no dir, only filename
> if ( (c=strrchr(ret, '/'))
>#ifdef MSVC5
>  || (c=strrchr(ret, '\\'))
>#endif
>  )
>  RETVAL_STRING(c+1,1); // backed to slash, move ahead 1 and return
> else
>  RETVAL_STRING(ret,1); // no slash, only filename

efree(ret);
}


###### it appears the only call to the following
###### is from php3_dirname() so I put the patch
###### there & suggest removing this.

<PHPAPI void _php3_dirname(char *str, int len) {
< register char *c;
<
< c = str + len - 1;
< while (*c == '/'
<#ifdef MSVC5
<     || *c == '\\'
<#endif
<  )
<  c--; /* strip trailing slashes */
< *(c + 1) = '\0';
< if ((c = strrchr(str, '/'))
<#ifdef MSVC5
<  || (c = strrchr(str, '\\'))
<#endif
<  )
<  *c='\0';
<}

void php3_dirname(INTERNAL_FUNCTION_PARAMETERS)
{
pval *str;
char *ret;
TLS_VARS;
> register char *c;

if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &str)) {
  WRONG_PARAM_COUNT;
}
convert_to_string(str);
ret = estrdup(str->value.str.val);

< _php3_dirname(ret,str->value.str.len);

> c=ret + len - 1;
> if ( *c=='/' // do we end with a slash?
>#ifdef MSVC5
>  || *c == '\\'
>#endif
>  || (c = strrchr(ret, '/')) // or found a slash?
>#ifdef MSVC5
>  || (c = strrchr(ret, '\\'))
>#endif
>  )
> {
>  if ( c == str ) // if only a slash remains (root dir)
>   c+1='\0'; // leave it
>  else
>   c='\0'; // else zap this slash
> } else {
>  *ret = '\0'; // if no slash, no dir, only filename
> }

RETVAL_STRING(ret,1);
efree(ret);
}

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [1998-12-21 14:06 UTC] rasmus
The correct operations of these functions should be...

dirname returns everything PRIOR to the last / or \ in the path.
basename returns everything AFTER the last / or \ in the path.

Reason for this is that we do not stat the file to check if it exists.  There are uses for these functions even in the case the directory or file is no there.  Therefor, we have no way to know if in some instances,
such as 'something' or '/something', it is a directory or file being refered to, even if there is a dot in the string, directories can also have dots.  So it is a matter of best guess.

Any other developers have comments?

I agree with this assessment.  And as the original ChangeLog entry stated, it is similar to the Bourne shell versions by the same names.  The functionality described above might be useful as a separate set of functions, but I would not consider it a bug in basename/dirname.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri May 10 06:01:31 2024 UTC