Skip to content

Commit b12b25a

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 b12b25a

File tree

1 file changed

+56
-10
lines changed

1 file changed

+56
-10
lines changed

ext/readline/readline_cli.c

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -599,13 +599,68 @@ 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+
{
624+
if (strncmp(environ[i], "XDG_", strlen("XDG_")) == 0) {
625+
use_xdg = true;
626+
break;
627+
}
628+
}
629+
630+
if (!use_xdg) {
631+
return history_file;
632+
}
633+
634+
xdg_data_home = getenv("XDG_DATA_HOME");
635+
if (!xdg_data_home) {
636+
xdg_data_home = "~/.local/share";
637+
}
638+
639+
expanded = tilde_expand(xdg_data_home);
640+
spprintf(&xdg_php_home, 0, "%s/php", expanded);
641+
free(expanded);
642+
643+
if (stat(xdg_php_home, &buffer) != 0 && mkdir(xdg_php_home, S_IRWXU) != 0) {
644+
efree(xdg_php_home);
645+
return history_file;
646+
}
647+
648+
efree(history_file);
649+
spprintf(&history_file, 0, "%s/history", xdg_php_home);
650+
efree(xdg_php_home);
651+
652+
return history_file;
653+
#endif
654+
}
655+
/* }}} */
656+
602657
static int readline_shell_run(void) /* {{{ */
603658
{
604659
char *line;
605660
size_t size = 4096, pos = 0, len;
606661
char *code = emalloc(size);
607662
zend_string *prompt = cli_get_prompt("php", '>');
608-
char *history_file;
663+
char *history_file = cli_history_file();
609664
int history_lines_to_write = 0;
610665

611666
if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
@@ -616,11 +671,6 @@ static int readline_shell_run(void) /* {{{ */
616671
zend_destroy_file_handle(&prepend_file);
617672
}
618673

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
624674
/* Install the default completion function for 'php -a'.
625675
*
626676
* But if readline_completion_function() was called by PHP code prior to the shell starting
@@ -717,11 +767,7 @@ static int readline_shell_run(void) /* {{{ */
717767

718768
php_last_char = '\0';
719769
}
720-
#ifdef PHP_WIN32
721770
efree(history_file);
722-
#else
723-
free(history_file);
724-
#endif
725771
efree(code);
726772
zend_string_release_ex(prompt, 0);
727773
return EG(exit_status);

0 commit comments

Comments
 (0)