Skip to content

Commit e7fba58

Browse files
committed
Make php -a history conform to XDG Base Directory Specification
Resolves GH-8546. To keep existing installations working the code first checks if a history file already exists at `~/.php_history`. If it does, then everything works as before. If `~/.php_history` does not exist, we check whether the system supports the XDG Base Directory Specification. If it doesn't we continue using `~/.php_history`; otherwise, we use a path that conforms to the XDG Base Directory Specification. We detect support for XDG Base Directory Specification by checking for environment variables that start with the `XDG_` prefix. This is analogous to what Composer does: composer/composer#1407 The specification can be found here: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
1 parent d7fc3ab commit e7fba58

File tree

1 file changed

+55
-10
lines changed

1 file changed

+55
-10
lines changed

ext/readline/readline_cli.c

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -599,13 +599,67 @@ static char **cli_code_completion(const char *text, int start, int end) /* {{{ *
599599
}
600600
/* }}} */
601601

602+
/* {{{ */
603+
static char *cli_history_file()
604+
{
605+
#ifdef PHP_WIN32
606+
char *history_file;
607+
spprintf(&history_file, MAX_PATH, "%s/.php_history", getenv("USERPROFILE"));
608+
return history_file;
609+
#else
610+
struct stat buffer;
611+
char *history_file, *expanded, *xdg_data_home, *xdg_php_home;
612+
bool use_xdg = false;
613+
614+
expanded = tilde_expand("~/.php_history");
615+
spprintf(&history_file, 0, "%s", expanded);
616+
free(expanded);
617+
618+
if (stat(history_file, &buffer) == 0) {
619+
return history_file;
620+
}
621+
622+
for (int i = 0; environ[i] != NULL; i++) {
623+
if (strncmp(environ[i], "XDG_", strlen("XDG_")) == 0) {
624+
use_xdg = true;
625+
break;
626+
}
627+
}
628+
629+
if (!use_xdg) {
630+
return history_file;
631+
}
632+
633+
xdg_data_home = getenv("XDG_DATA_HOME");
634+
if (!xdg_data_home) {
635+
xdg_data_home = "~/.local/share";
636+
}
637+
638+
expanded = tilde_expand(xdg_data_home);
639+
spprintf(&xdg_php_home, 0, "%s/php", expanded);
640+
free(expanded);
641+
642+
if (stat(xdg_php_home, &buffer) != 0 && mkdir(xdg_php_home, S_IRWXU) != 0) {
643+
efree(xdg_php_home);
644+
return history_file;
645+
}
646+
647+
efree(history_file);
648+
spprintf(&history_file, 0, "%s/history", xdg_php_home);
649+
efree(xdg_php_home);
650+
651+
return history_file;
652+
#endif
653+
}
654+
/* }}} */
655+
602656
static int readline_shell_run(void) /* {{{ */
603657
{
604658
char *line;
605659
size_t size = 4096, pos = 0, len;
606660
char *code = emalloc(size);
607661
zend_string *prompt = cli_get_prompt("php", '>');
608-
char *history_file;
662+
char *history_file = cli_history_file();
609663
int history_lines_to_write = 0;
610664

611665
if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
@@ -616,11 +670,6 @@ static int readline_shell_run(void) /* {{{ */
616670
zend_destroy_file_handle(&prepend_file);
617671
}
618672

619-
#ifndef PHP_WIN32
620-
history_file = tilde_expand("~/.php_history");
621-
#else
622-
spprintf(&history_file, MAX_PATH, "%s/.php_history", getenv("USERPROFILE"));
623-
#endif
624673
/* Install the default completion function for 'php -a'.
625674
*
626675
* But if readline_completion_function() was called by PHP code prior to the shell starting
@@ -717,11 +766,7 @@ static int readline_shell_run(void) /* {{{ */
717766

718767
php_last_char = '\0';
719768
}
720-
#ifdef PHP_WIN32
721769
efree(history_file);
722-
#else
723-
free(history_file);
724-
#endif
725770
efree(code);
726771
zend_string_release_ex(prompt, 0);
727772
return EG(exit_status);

0 commit comments

Comments
 (0)