├── .devcontainer └── devcontainer.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── update-remote.yml ├── .gitignore ├── .htaccess ├── 403.php ├── 404.php ├── CODE_OF_CONDUCT.md ├── LICENSE ├── assets ├── analytics.php ├── images │ ├── favicon.png │ ├── flags │ │ ├── ar.svg │ │ ├── az.png │ │ ├── cz.svg │ │ ├── de.svg │ │ ├── eo.svg │ │ ├── es.svg │ │ ├── fr.svg │ │ ├── gr.svg │ │ ├── id.svg │ │ ├── it.svg │ │ ├── lu.svg │ │ ├── nl.svg │ │ ├── ru.svg │ │ ├── tr.svg │ │ ├── uk.svg │ │ └── zh_tw.svg │ ├── music_note.png │ └── no_song.png ├── js │ ├── alpine.min.js │ ├── playing.js │ ├── scripts.js │ └── spotify-web-api.js ├── lang │ ├── ar.php │ ├── az.php │ ├── cz.php │ ├── de.php │ ├── en.php │ ├── eo.php │ ├── es.php │ ├── fr.php │ ├── gr.php │ ├── id.php │ ├── it.php │ ├── jp.php │ ├── lu.php │ ├── nl.php │ ├── pl.php │ ├── ru.php │ ├── tr.php │ └── zh_tw.php └── links.php ├── composer.json ├── composer.lock ├── example.env ├── generate_miniplayer.php ├── index.php ├── lang.php ├── lib ├── spotify_api.php └── spotify_session.php ├── login.php ├── miniplayer.php ├── playing.php ├── readme.md ├── screenshots ├── miniplayer.png └── regular.png ├── token.php └── vendor ├── autoload.php ├── composer ├── ClassLoader.php ├── InstalledVersions.php ├── LICENSE ├── autoload_classmap.php ├── autoload_files.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php ├── installed.json ├── installed.php └── platform_check.php ├── graham-campbell └── result-type │ ├── LICENSE │ ├── composer.json │ └── src │ ├── Error.php │ ├── Result.php │ └── Success.php ├── jwilsson └── spotify-web-api-php │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── LICENSE.md │ ├── README.md │ ├── composer.json │ ├── docs │ ├── README.md │ └── getting-started.md │ ├── phpcs.xml │ ├── phpunit.php │ ├── phpunit.xml.dist │ ├── src │ ├── Request.php │ ├── Session.php │ ├── SpotifyWebAPI.php │ ├── SpotifyWebAPIAuthException.php │ ├── SpotifyWebAPIException.php │ └── cacert.pem │ └── tests │ ├── RequestTest.php │ ├── SessionTest.php │ ├── SpotifyWebAPITest.php │ └── fixtures │ ├── access-token.json │ ├── album-tracks.json │ ├── album.json │ ├── albums.json │ ├── artist-related-artists.json │ ├── artist-top-tracks.json │ ├── artist.json │ ├── artists.json │ ├── audio-analysis.json │ ├── audio-features.json │ ├── available-genre-seeds.json │ ├── categories-list.json │ ├── category-playlists.json │ ├── category.json │ ├── featured-playlists.json │ ├── new-releases.json │ ├── recently-played.json │ ├── recommendations.json │ ├── refresh-token-no-refresh-token.json │ ├── refresh-token.json │ ├── search-album.json │ ├── snapshot-id.json │ ├── top-artists-and-tracks.json │ ├── track.json │ ├── tracks.json │ ├── user-albums-contains.json │ ├── user-current-playback-info.json │ ├── user-current-track.json │ ├── user-devices.json │ ├── user-followed-artists.json │ ├── user-follows-playlist.json │ ├── user-follows.json │ ├── user-playlist-tracks.json │ ├── user-playlist.json │ ├── user-playlists.json │ ├── user-tracks-contains.json │ ├── user-tracks.json │ ├── user.json │ └── users-follows-playlist.json ├── phpoption └── phpoption │ ├── LICENSE │ ├── Makefile │ ├── composer.json │ └── src │ └── PhpOption │ ├── LazyOption.php │ ├── None.php │ ├── Option.php │ └── Some.php ├── symfony ├── polyfill-ctype │ ├── Ctype.php │ ├── LICENSE │ ├── README.md │ ├── bootstrap.php │ ├── bootstrap80.php │ └── composer.json ├── polyfill-mbstring │ ├── LICENSE │ ├── Mbstring.php │ ├── README.md │ ├── Resources │ │ └── unidata │ │ │ ├── lowerCase.php │ │ │ ├── titleCaseRegexp.php │ │ │ └── upperCase.php │ ├── bootstrap.php │ ├── bootstrap80.php │ └── composer.json └── polyfill-php80 │ ├── LICENSE │ ├── Php80.php │ ├── README.md │ ├── Resources │ └── stubs │ │ ├── Attribute.php │ │ ├── Stringable.php │ │ ├── UnhandledMatchError.php │ │ └── ValueError.php │ ├── bootstrap.php │ └── composer.json └── vlucas └── phpdotenv ├── LICENSE ├── composer.json └── src ├── Dotenv.php ├── Exception ├── ExceptionInterface.php ├── InvalidEncodingException.php ├── InvalidFileException.php ├── InvalidPathException.php └── ValidationException.php ├── Loader ├── Loader.php ├── LoaderInterface.php └── Resolver.php ├── Parser ├── Entry.php ├── EntryParser.php ├── Lexer.php ├── Lines.php ├── Parser.php ├── ParserInterface.php └── Value.php ├── Repository ├── Adapter │ ├── AdapterInterface.php │ ├── ApacheAdapter.php │ ├── ArrayAdapter.php │ ├── EnvConstAdapter.php │ ├── GuardedWriter.php │ ├── ImmutableWriter.php │ ├── MultiReader.php │ ├── MultiWriter.php │ ├── PutenvAdapter.php │ ├── ReaderInterface.php │ ├── ReplacingWriter.php │ ├── ServerConstAdapter.php │ └── WriterInterface.php ├── AdapterRepository.php ├── RepositoryBuilder.php └── RepositoryInterface.php ├── Store ├── File │ ├── Paths.php │ └── Reader.php ├── FileStore.php ├── StoreBuilder.php ├── StoreInterface.php └── StringStore.php ├── Util ├── Regex.php └── Str.php └── Validator.php /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/php 3 | { 4 | "name": "PHP", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/php:1-8.2-bullseye", 7 | 8 | // Features to add to the dev container. More info: https://containers.dev/features. 9 | // "features": {}, 10 | 11 | // Configure tool-specific properties. 12 | // "customizations": {}, 13 | 14 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 15 | "forwardPorts": [ 16 | 8080 17 | ], 18 | "features": { 19 | "ghcr.io/devcontainers-contrib/features/zsh-plugins:0": {}, 20 | "ghcr.io/stuartleeks/dev-container-features/shell-history:0": {} 21 | }, 22 | 23 | // Use 'postCreateCommand' to run commands after the container is created. 24 | "postCreateCommand": "sudo a2enmod rewrite && sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html && service apache2 restart" 25 | 26 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 27 | // "remoteUser": "root" 28 | } 29 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: busybox11 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: busybox11 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['paypal.me/busybox11'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/update-remote.yml: -------------------------------------------------------------------------------- 1 | name: Update remote server 2 | on: [push] 3 | jobs: 4 | 5 | update: 6 | name: Update 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: executing remote ssh commands using password 10 | uses: appleboy/ssh-action@master 11 | env: 12 | SCRIPT_STR: ${{ secrets.SSH_SCRIPT }} 13 | with: 14 | host: ${{ secrets.SSH_SERVER }} 15 | username: ${{ secrets.SSH_USERNAME }} 16 | key: ${{ secrets.SSH_PRIVATE_KEY }} 17 | envs: SCRIPT_STR, GITHUB_REF_NAME 18 | script: | 19 | $SCRIPT_STR $GITHUB_REF_NAME 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .DS_Store -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | ErrorDocument 404 /404.php 2 | ErrorDocument 403 /403.php 3 | 4 | RedirectMatch 403 /.env 5 | 6 | # vendor 7 | RedirectMatch 403 /vendor(/|$) 8 | 9 | # disable .git folder 10 | RedirectMatch 404 /\.git 11 | 12 | # disable .devcontainer, .vscode, .github folders 13 | RedirectMatch 404 /(\.devcontainer|\.vscode|\.github) 14 | 15 | # disable directory browsing 16 | Options -Indexes 17 | 18 | # disable server signature 19 | ServerSignature Off 20 | 21 | # disable php errors 22 | php_flag display_errors Off 23 | php_flag display_startup_errors Off 24 | -------------------------------------------------------------------------------- /403.php: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | <?= Error; ?> 403 - NowPlaying 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 54 | 55 | 59 | 60 | 61 | 62 |
63 | Logo 64 | 65 |

403

66 |

67 |
68 | 69 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /404.php: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | <?= Error; ?> 404 - NowPlaying 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 54 | 55 | 59 | 60 | 61 | 62 |
63 | Logo 64 | 65 |

404

66 |

67 |
68 | 69 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at the Discord server. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /assets/analytics.php: -------------------------------------------------------------------------------- 1 | load(); 8 | } 9 | 10 | function getAnalyticsScript() 11 | { 12 | if (isset($_ENV['ANALYTICS_SCRIPT'])) { 13 | return $_ENV['ANALYTICS_SCRIPT']; 14 | } 15 | 16 | return ""; 17 | } -------------------------------------------------------------------------------- /assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/assets/images/favicon.png -------------------------------------------------------------------------------- /assets/images/flags/az.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/assets/images/flags/az.png -------------------------------------------------------------------------------- /assets/images/flags/cz.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/de.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/eo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/es.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/fr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/gr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/id.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/it.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/lu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/nl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /assets/images/flags/ru.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/tr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/uk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/flags/zh_tw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/music_note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/assets/images/music_note.png -------------------------------------------------------------------------------- /assets/images/no_song.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/assets/images/no_song.png -------------------------------------------------------------------------------- /assets/js/playing.js: -------------------------------------------------------------------------------- 1 | // Check if cookie refreshToken is set 2 | let cookie = document.cookie; 3 | const cookieHasRefreshToken = cookie.includes("refreshToken"); 4 | 5 | const refreshTokenParam = urlParams.get('refreshToken'); 6 | 7 | if (!cookieHasRefreshToken && !refreshTokenParam) { window.location.replace('login.php'); } 8 | 9 | let refreshTime = readCookie('refreshTime'); 10 | let spotifyApi; 11 | 12 | async function fetchAccessToken() { 13 | if (!cookieHasRefreshToken && !refreshTokenParam) { 14 | // Redirect to login page 15 | window.location.replace('login.php'); 16 | return; 17 | } 18 | 19 | let targetUrl = 'token.php?action=refresh&response=data'; 20 | if (refreshTokenParam) { 21 | targetUrl += `&refreshToken=${refreshTokenParam}`; 22 | } 23 | 24 | const response = await fetch(targetUrl); 25 | const data = await response.json(); 26 | 27 | return data; 28 | } 29 | 30 | const useSmallAlbumCover = window.playerConfig?.useSmallAlbumCover ?? false; 31 | 32 | document.addEventListener('alpine:init', x => { 33 | const serverPlaybackState = window.serverPlaybackState || null; 34 | 35 | Alpine.store('player', { 36 | init() { 37 | spotifyApi = new SpotifyWebApi(); 38 | 39 | // Don't reuse access token if refreshToken param is passed 40 | // so that we force refreshing with a new token on load 41 | if (cookieHasRefreshToken && !refreshTokenParam) { 42 | spotifyApi.setAccessToken(readCookie('accessToken')); 43 | 44 | this.poolingLoop(); 45 | } else if (refreshTokenParam) { 46 | this.refreshToken().then(() => { 47 | this.poolingLoop(); 48 | }); 49 | } 50 | 51 | if (serverPlaybackState) { 52 | this.handleChange(serverPlaybackState); 53 | } 54 | }, 55 | 56 | playbackObj: serverPlaybackState || {}, 57 | lastPlaybackObj: {}, 58 | 59 | targetImg: serverPlaybackState?.item?.album?.images[0]?.url || 'assets/images/no_song.png', 60 | 61 | async poolingLoop() { 62 | setInterval(async () => { 63 | await this.fetchState(); 64 | }, 1000) 65 | }, 66 | 67 | async refreshToken() { 68 | console.log('Refreshing token...'); 69 | 70 | const data = await fetchAccessToken(); 71 | 72 | if (data.accessToken) { 73 | spotifyApi.setAccessToken(data.accessToken); 74 | refreshTime = data.refreshTime; 75 | console.log('Refreshed token'); 76 | } else { 77 | console.log('Failed to refresh token'); 78 | 79 | // Redirect to login page 80 | window.location.replace('login.php'); 81 | } 82 | }, 83 | 84 | async fetchState() { 85 | if (Math.floor(Date.now() / 1000) >= refreshTime) { 86 | await this.refreshToken(); 87 | } 88 | 89 | const response = await spotifyApi.getMyCurrentPlaybackState({ 90 | additional_types: "episode" 91 | }); 92 | if (response) { 93 | this.handleChange(response); 94 | } 95 | }, 96 | 97 | handleChange(obj) { 98 | this.lastPlaybackObj = this.playbackObj; 99 | this.playbackObj = obj; 100 | 101 | const artists = this.playbackObj.item?.artists || [{ name: this.playbackObj.item?.show?.publisher }] 102 | 103 | if (this.playbackObj.item?.name) { 104 | document.title = `${this.playbackObj.item?.name} - ${artists[0].name} - NowPlaying`; 105 | } 106 | 107 | this._handleAlbumArtChange(); 108 | 109 | // Set DOM classes 110 | document.querySelector('body').classList.toggle('np_music_playing', this.playbackObj.is_playing); 111 | document.querySelector('body').classList.toggle('np_music_paused', !this.playbackObj.is_playing); 112 | }, 113 | 114 | _handleAlbumArtChange() { 115 | const imgsArr = this.playbackObj.item?.album?.images || this.playbackObj.item?.images; 116 | const targetImg = (useSmallAlbumCover) ? imgsArr[imgsArr.length - 2]?.url : imgsArr[0]?.url; 117 | 118 | const lastImgsArr = this.lastPlaybackObj.item?.album?.images || this.lastPlaybackObj.item?.images; 119 | if (lastImgsArr === undefined) { 120 | this.targetImg = targetImg; 121 | return; 122 | } 123 | const lastTargetImg = (useSmallAlbumCover) ? lastImgsArr[lastImgsArr.length - 2]?.url : lastImgsArr[0]?.url; 124 | 125 | if (targetImg !== lastTargetImg) { 126 | // Load image in new element and then set it on the target 127 | const img = new Image(); 128 | img.src = (targetImg !== undefined) ? targetImg : 'assets/images/no_song.png' 129 | img.onload = () => { 130 | this.targetImg = img.src; 131 | } 132 | } 133 | } 134 | }) 135 | }) -------------------------------------------------------------------------------- /assets/js/scripts.js: -------------------------------------------------------------------------------- 1 | const urlParams = new URLSearchParams(window.location.search); 2 | 3 | if (localStorage.getItem('deviceId') == null) { 4 | function makeId(length) { 5 | var out = ''; 6 | var numbers = '0123456789'; 7 | for ( let i = 0; i < length; i++ ) { 8 | out += numbers.charAt(Math.floor(Math.random() * numbers.length)); 9 | } 10 | return out; 11 | } 12 | 13 | localStorage.setItem('deviceId', makeId(4)) 14 | } 15 | 16 | function msToTime(duration) { 17 | let seconds = parseInt((duration / 1000) % 60), 18 | minutes = parseInt((duration / (1000 * 60)) % 60) 19 | 20 | minutes = (minutes < 10) ? "0" + minutes : minutes; 21 | seconds = (seconds < 10) ? "0" + seconds : seconds; 22 | 23 | if (minutes !== NaN && seconds !== NaN) { 24 | return minutes + ":" + seconds; 25 | } else { 26 | return undefined; 27 | } 28 | } 29 | 30 | function readCookie(name) { 31 | var nameEQ = name + "="; 32 | var ca = document.cookie.split(';'); 33 | for (var i = 0; i < ca.length; i++) { 34 | var c = ca[i]; 35 | while (c.charAt(0) == ' ') c = c.substring(1, c.length); 36 | if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 37 | } 38 | return null; 39 | } 40 | 41 | function setCookie(cname, cvalue, exdays) { 42 | var d = new Date(); 43 | d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); 44 | var expires = "expires=" + d.toGMTString(); 45 | document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; 46 | } 47 | 48 | /* WakeLock */ 49 | let wakelock = null; 50 | 51 | /* Prevent screen from sleeping */ 52 | function getWakelock() { 53 | if ('wakeLock' in navigator) { 54 | navigator.wakeLock.request('screen').then(function (wakeLock) { 55 | wakelock = wakeLock; 56 | }).catch(function (err) { 57 | console.log(`Failed to request wake lock: ${err}`); 58 | }); 59 | } 60 | } 61 | 62 | /* Release the wake lock */ 63 | function releaseWakelock() { 64 | if (wakelock !== null) { 65 | wakelock.release(); 66 | wakelock = null; 67 | } 68 | } 69 | 70 | /* Fullscreen */ 71 | let elem = document.documentElement; 72 | 73 | /* View in fullscreen */ 74 | function openFullscreen() { 75 | if (elem.requestFullscreen) { 76 | elem.requestFullscreen(); 77 | } else if (elem.mozRequestFullScreen) { /* Firefox */ 78 | elem.mozRequestFullScreen(); 79 | } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ 80 | elem.webkitRequestFullscreen(); 81 | } else if (elem.msRequestFullscreen) { /* IE/Edge */ 82 | elem.msRequestFullscreen(); 83 | } 84 | getWakelock(); 85 | } 86 | 87 | /* Close fullscreen */ 88 | function closeFullscreen() { 89 | if (document.exitFullscreen) { 90 | document.exitFullscreen(); 91 | } else if (document.mozCancelFullScreen) { /* Firefox */ 92 | document.mozCancelFullScreen(); 93 | } else if (document.webkitExitFullscreen) { /* Chrome, Safari and Opera */ 94 | document.webkitExitFullscreen(); 95 | } else if (document.msExitFullscreen) { /* IE/Edge */ 96 | document.msExitFullscreen(); 97 | } 98 | releaseWakelock(); 99 | } 100 | 101 | function fullscreen() { 102 | let isFullscreen = document.fullscreen; 103 | (isFullscreen) ? closeFullscreen() : openFullscreen() 104 | } 105 | 106 | function theme() { 107 | if (localStorage.getItem('theme') == null || localStorage.getItem('theme') == 'original') { 108 | localStorage.setItem('theme', 'test'); 109 | $('#playingcss-test').attr('rel', 'stylesheet'); 110 | } else { 111 | localStorage.setItem('theme', 'original'); 112 | $('#playingcss-test').attr('rel', 'stylesheet alternate'); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /assets/lang/ar.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/lang/az.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/cz.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/de.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/en.php: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /assets/lang/eo.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /assets/lang/es.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/fr.php: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /assets/lang/gr.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/id.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/it.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/jp.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /assets/lang/lu.php: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /assets/lang/nl.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /assets/lang/pl.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /assets/lang/ru.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /assets/lang/tr.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /assets/lang/zh_tw.php: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /assets/links.php: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "jwilsson/spotify-web-api-php": "5.0.3", 4 | "vlucas/phpdotenv": "5.4.1" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | CLIENT_ID= 2 | CLIENT_SECRET= 3 | REDIRECT_URI= 4 | ANALYTICS_SCRIPT= 5 | -------------------------------------------------------------------------------- /lang.php: -------------------------------------------------------------------------------- 1 | 86 | -------------------------------------------------------------------------------- /lib/spotify_api.php: -------------------------------------------------------------------------------- 1 | load(); 7 | } 8 | 9 | $session = new SpotifyWebAPI\Session( 10 | $_ENV['CLIENT_ID'], 11 | $_ENV['CLIENT_SECRET'], 12 | $_ENV['REDIRECT_URI'] 13 | ); -------------------------------------------------------------------------------- /login.php: -------------------------------------------------------------------------------- 1 | load(); 8 | 9 | if ($_GET['generateMiniPlayer'] == 'true') { 10 | $_SESSION['generateMiniPlayer'] = true; 11 | } else { 12 | $_SESSION['generateMiniPlayer'] = false; 13 | } 14 | 15 | $options = [ 16 | 'scope' => [ 17 | 'user-read-currently-playing', 18 | 'user-read-playback-state', 19 | 'streaming' 20 | ], 21 | ]; 22 | 23 | header('Location: ' . $session->getAuthorizeUrl($options)); 24 | die(); 25 | ?> 26 | 27 | -------------------------------------------------------------------------------- /screenshots/miniplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/screenshots/miniplayer.png -------------------------------------------------------------------------------- /screenshots/regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/busybox11/NowPlaying-for-Spotify/5b5633b5185c512d75e54753e4db1eb27ead4dad/screenshots/regular.png -------------------------------------------------------------------------------- /token.php: -------------------------------------------------------------------------------- 1 | load(); 8 | 9 | // Use the passed GET refreshToken parameter first 10 | // in case this is used as a not logged in miniplayer 11 | $refreshToken = $_GET['refreshToken'] ?? $_COOKIE['refreshToken'] ?? null; 12 | 13 | if (!isset($_GET['action'])) { 14 | $session->requestAccessToken($_GET['code']); 15 | 16 | $accessToken = $session->getAccessToken(); 17 | $refreshToken = $session->getRefreshToken(); 18 | $refreshTime = time() + 3600; 19 | 20 | setcookie('accessToken', $accessToken, time() + 3600); 21 | setcookie('refreshTime', time() + 3600, time() + (3600 * 365)); 22 | setcookie('refreshToken', $refreshToken, time() + (3600 * 365)); 23 | } elseif ($_GET['action'] == "refresh") { 24 | $session->refreshAccessToken($refreshToken); 25 | 26 | $accessToken = $session->getAccessToken(); 27 | $refreshToken = $session->getRefreshToken(); 28 | $refreshTime = time() + 3600; 29 | 30 | if (!$_GET['refreshToken']) { 31 | // No need to set cookies if a refresh token is passed via a GET parameter 32 | // We only want to get the necessary tokens and data from a fetch() call 33 | setcookie('accessToken', $accessToken, time() + 3600); 34 | setcookie('refreshTime', time() + 3600, time() + (3600 * 365)); 35 | setcookie('refreshToken', $refreshToken, time() + (3600 * 365)); 36 | } 37 | } 38 | 39 | if (isset($_GET['response']) && $_GET['response'] == "data") { 40 | echo json_encode(array( 41 | 'accessToken' => $accessToken, 42 | 'refreshToken' => $refreshToken, 43 | 'refreshTime' => $refreshTime, 44 | )); 45 | die(); 46 | } else { 47 | if ($_SESSION['generateMiniPlayer'] == true) { 48 | header('Location: generate_miniplayer.php'); 49 | die(); 50 | } 51 | 52 | header('Location: playing.php'); 53 | die(); 54 | } 55 | ?> 56 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 10 | 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 11 | 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', 12 | 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', 13 | 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', 14 | ); 15 | -------------------------------------------------------------------------------- /vendor/composer/autoload_files.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/symfony/polyfill-php80/bootstrap.php', 10 | '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 11 | '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', 12 | ); 13 | -------------------------------------------------------------------------------- /vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/symfony/polyfill-php80'), 10 | 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 11 | 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), 12 | 'SpotifyWebAPI\\' => array($vendorDir . '/jwilsson/spotify-web-api-php/src'), 13 | 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'), 14 | 'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'), 15 | 'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), 16 | ); 17 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 32 | if ($useStaticLoader) { 33 | require __DIR__ . '/autoload_static.php'; 34 | 35 | call_user_func(\Composer\Autoload\ComposerStaticInit6222f2634dcca386b2c2c160ced4f088::getInitializer($loader)); 36 | } else { 37 | $map = require __DIR__ . '/autoload_namespaces.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->set($namespace, $path); 40 | } 41 | 42 | $map = require __DIR__ . '/autoload_psr4.php'; 43 | foreach ($map as $namespace => $path) { 44 | $loader->setPsr4($namespace, $path); 45 | } 46 | 47 | $classMap = require __DIR__ . '/autoload_classmap.php'; 48 | if ($classMap) { 49 | $loader->addClassMap($classMap); 50 | } 51 | } 52 | 53 | $loader->register(true); 54 | 55 | if ($useStaticLoader) { 56 | $includeFiles = Composer\Autoload\ComposerStaticInit6222f2634dcca386b2c2c160ced4f088::$files; 57 | } else { 58 | $includeFiles = require __DIR__ . '/autoload_files.php'; 59 | } 60 | foreach ($includeFiles as $fileIdentifier => $file) { 61 | composerRequire6222f2634dcca386b2c2c160ced4f088($fileIdentifier, $file); 62 | } 63 | 64 | return $loader; 65 | } 66 | } 67 | 68 | function composerRequire6222f2634dcca386b2c2c160ced4f088($fileIdentifier, $file) 69 | { 70 | if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 71 | require $file; 72 | 73 | $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', 11 | '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 12 | '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', 13 | ); 14 | 15 | public static $prefixLengthsPsr4 = array ( 16 | 'S' => 17 | array ( 18 | 'Symfony\\Polyfill\\Php80\\' => 23, 19 | 'Symfony\\Polyfill\\Mbstring\\' => 26, 20 | 'Symfony\\Polyfill\\Ctype\\' => 23, 21 | 'SpotifyWebAPI\\' => 14, 22 | ), 23 | 'P' => 24 | array ( 25 | 'PhpOption\\' => 10, 26 | ), 27 | 'G' => 28 | array ( 29 | 'GrahamCampbell\\ResultType\\' => 26, 30 | ), 31 | 'D' => 32 | array ( 33 | 'Dotenv\\' => 7, 34 | ), 35 | ); 36 | 37 | public static $prefixDirsPsr4 = array ( 38 | 'Symfony\\Polyfill\\Php80\\' => 39 | array ( 40 | 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', 41 | ), 42 | 'Symfony\\Polyfill\\Mbstring\\' => 43 | array ( 44 | 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', 45 | ), 46 | 'Symfony\\Polyfill\\Ctype\\' => 47 | array ( 48 | 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', 49 | ), 50 | 'SpotifyWebAPI\\' => 51 | array ( 52 | 0 => __DIR__ . '/..' . '/jwilsson/spotify-web-api-php/src', 53 | ), 54 | 'PhpOption\\' => 55 | array ( 56 | 0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption', 57 | ), 58 | 'GrahamCampbell\\ResultType\\' => 59 | array ( 60 | 0 => __DIR__ . '/..' . '/graham-campbell/result-type/src', 61 | ), 62 | 'Dotenv\\' => 63 | array ( 64 | 0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src', 65 | ), 66 | ); 67 | 68 | public static $classMap = array ( 69 | 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', 70 | 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 71 | 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', 72 | 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', 73 | 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', 74 | ); 75 | 76 | public static function getInitializer(ClassLoader $loader) 77 | { 78 | return \Closure::bind(function () use ($loader) { 79 | $loader->prefixLengthsPsr4 = ComposerStaticInit6222f2634dcca386b2c2c160ced4f088::$prefixLengthsPsr4; 80 | $loader->prefixDirsPsr4 = ComposerStaticInit6222f2634dcca386b2c2c160ced4f088::$prefixDirsPsr4; 81 | $loader->classMap = ComposerStaticInit6222f2634dcca386b2c2c160ced4f088::$classMap; 82 | 83 | }, null, ClassLoader::class); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /vendor/composer/installed.php: -------------------------------------------------------------------------------- 1 | array( 3 | 'pretty_version' => 'dev-master', 4 | 'version' => 'dev-master', 5 | 'type' => 'library', 6 | 'install_path' => __DIR__ . '/../../', 7 | 'aliases' => array(), 8 | 'reference' => '2d43047aeee42472a556ebe7ddcd6b6e513e31b4', 9 | 'name' => '__root__', 10 | 'dev' => true, 11 | ), 12 | 'versions' => array( 13 | '__root__' => array( 14 | 'pretty_version' => 'dev-master', 15 | 'version' => 'dev-master', 16 | 'type' => 'library', 17 | 'install_path' => __DIR__ . '/../../', 18 | 'aliases' => array(), 19 | 'reference' => '2d43047aeee42472a556ebe7ddcd6b6e513e31b4', 20 | 'dev_requirement' => false, 21 | ), 22 | 'graham-campbell/result-type' => array( 23 | 'pretty_version' => 'v1.0.2', 24 | 'version' => '1.0.2.0', 25 | 'type' => 'library', 26 | 'install_path' => __DIR__ . '/../graham-campbell/result-type', 27 | 'aliases' => array(), 28 | 'reference' => '84afea85c6841deeea872f36249a206e878a5de0', 29 | 'dev_requirement' => false, 30 | ), 31 | 'jwilsson/spotify-web-api-php' => array( 32 | 'pretty_version' => '2.6.1', 33 | 'version' => '2.6.1.0', 34 | 'type' => 'library', 35 | 'install_path' => __DIR__ . '/../jwilsson/spotify-web-api-php', 36 | 'aliases' => array(), 37 | 'reference' => 'ed2b32d73125b692f74b6b852ba56e156757c96e', 38 | 'dev_requirement' => false, 39 | ), 40 | 'phpoption/phpoption' => array( 41 | 'pretty_version' => '1.8.0', 42 | 'version' => '1.8.0.0', 43 | 'type' => 'library', 44 | 'install_path' => __DIR__ . '/../phpoption/phpoption', 45 | 'aliases' => array(), 46 | 'reference' => '5455cb38aed4523f99977c4a12ef19da4bfe2a28', 47 | 'dev_requirement' => false, 48 | ), 49 | 'symfony/polyfill-ctype' => array( 50 | 'pretty_version' => 'v1.23.0', 51 | 'version' => '1.23.0.0', 52 | 'type' => 'library', 53 | 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 54 | 'aliases' => array(), 55 | 'reference' => '46cd95797e9df938fdd2b03693b5fca5e64b01ce', 56 | 'dev_requirement' => false, 57 | ), 58 | 'symfony/polyfill-mbstring' => array( 59 | 'pretty_version' => 'v1.23.1', 60 | 'version' => '1.23.1.0', 61 | 'type' => 'library', 62 | 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 63 | 'aliases' => array(), 64 | 'reference' => '9174a3d80210dca8daa7f31fec659150bbeabfc6', 65 | 'dev_requirement' => false, 66 | ), 67 | 'symfony/polyfill-php80' => array( 68 | 'pretty_version' => 'v1.23.1', 69 | 'version' => '1.23.1.0', 70 | 'type' => 'library', 71 | 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 72 | 'aliases' => array(), 73 | 'reference' => '1100343ed1a92e3a38f9ae122fc0eb21602547be', 74 | 'dev_requirement' => false, 75 | ), 76 | 'vlucas/phpdotenv' => array( 77 | 'pretty_version' => 'v5.3.0', 78 | 'version' => '5.3.0.0', 79 | 'type' => 'library', 80 | 'install_path' => __DIR__ . '/../vlucas/phpdotenv', 81 | 'aliases' => array(), 82 | 'reference' => 'b3eac5c7ac896e52deab4a99068e3f4ab12d9e56', 83 | 'dev_requirement' => false, 84 | ), 85 | ), 86 | ); 87 | -------------------------------------------------------------------------------- /vendor/composer/platform_check.php: -------------------------------------------------------------------------------- 1 | = 70103)) { 8 | $issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.3". You are running ' . PHP_VERSION . '.'; 9 | } 10 | 11 | if ($issues) { 12 | if (!headers_sent()) { 13 | header('HTTP/1.1 500 Internal Server Error'); 14 | } 15 | if (!ini_get('display_errors')) { 16 | if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { 17 | fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); 18 | } elseif (!headers_sent()) { 19 | echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; 20 | } 21 | } 22 | trigger_error( 23 | 'Composer detected issues in your platform: ' . implode(' ', $issues), 24 | E_USER_ERROR 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /vendor/graham-campbell/result-type/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Graham Campbell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/graham-campbell/result-type/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graham-campbell/result-type", 3 | "description": "An Implementation Of The Result Type", 4 | "keywords": ["result", "result-type", "Result", "Result Type", "Result-Type", "Graham Campbell", "GrahamCampbell"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Graham Campbell", 9 | "email": "hello@gjcampbell.co.uk" 10 | } 11 | ], 12 | "require": { 13 | "php": "^7.0 || ^8.0", 14 | "phpoption/phpoption": "^1.8" 15 | }, 16 | "require-dev": { 17 | "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "GrahamCampbell\\ResultType\\": "src/" 22 | } 23 | }, 24 | "autoload-dev": { 25 | "psr-4": { 26 | "GrahamCampbell\\Tests\\ResultType\\": "tests/" 27 | } 28 | }, 29 | "config": { 30 | "preferred-install": "dist" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /vendor/graham-campbell/result-type/src/Error.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | 14 | namespace GrahamCampbell\ResultType; 15 | 16 | use PhpOption\None; 17 | use PhpOption\Some; 18 | 19 | /** 20 | * @template T 21 | * @template E 22 | * @extends \GrahamCampbell\ResultType\Result 23 | */ 24 | final class Error extends Result 25 | { 26 | /** 27 | * @var E 28 | */ 29 | private $value; 30 | 31 | /** 32 | * Internal constructor for an error value. 33 | * 34 | * @param E $value 35 | * 36 | * @return void 37 | */ 38 | private function __construct($value) 39 | { 40 | $this->value = $value; 41 | } 42 | 43 | /** 44 | * Create a new error value. 45 | * 46 | * @template F 47 | * 48 | * @param F $value 49 | * 50 | * @return \GrahamCampbell\ResultType\Result 51 | */ 52 | public static function create($value) 53 | { 54 | return new self($value); 55 | } 56 | 57 | /** 58 | * Get the success option value. 59 | * 60 | * @return \PhpOption\Option 61 | */ 62 | public function success() 63 | { 64 | return None::create(); 65 | } 66 | 67 | /** 68 | * Map over the success value. 69 | * 70 | * @template S 71 | * 72 | * @param callable(T):S $f 73 | * 74 | * @return \GrahamCampbell\ResultType\Result 75 | */ 76 | public function map(callable $f) 77 | { 78 | return self::create($this->value); 79 | } 80 | 81 | /** 82 | * Flat map over the success value. 83 | * 84 | * @template S 85 | * @template F 86 | * 87 | * @param callable(T):\GrahamCampbell\ResultType\Result $f 88 | * 89 | * @return \GrahamCampbell\ResultType\Result 90 | */ 91 | public function flatMap(callable $f) 92 | { 93 | /** @var \GrahamCampbell\ResultType\Result */ 94 | return self::create($this->value); 95 | } 96 | 97 | /** 98 | * Get the error option value. 99 | * 100 | * @return \PhpOption\Option 101 | */ 102 | public function error() 103 | { 104 | return Some::create($this->value); 105 | } 106 | 107 | /** 108 | * Map over the error value. 109 | * 110 | * @template F 111 | * 112 | * @param callable(E):F $f 113 | * 114 | * @return \GrahamCampbell\ResultType\Result 115 | */ 116 | public function mapError(callable $f) 117 | { 118 | return self::create($f($this->value)); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /vendor/graham-campbell/result-type/src/Result.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | 14 | namespace GrahamCampbell\ResultType; 15 | 16 | /** 17 | * @template T 18 | * @template E 19 | */ 20 | abstract class Result 21 | { 22 | /** 23 | * Get the success option value. 24 | * 25 | * @return \PhpOption\Option 26 | */ 27 | abstract public function success(); 28 | 29 | /** 30 | * Map over the success value. 31 | * 32 | * @template S 33 | * 34 | * @param callable(T):S $f 35 | * 36 | * @return \GrahamCampbell\ResultType\Result 37 | */ 38 | abstract public function map(callable $f); 39 | 40 | /** 41 | * Flat map over the success value. 42 | * 43 | * @template S 44 | * @template F 45 | * 46 | * @param callable(T):\GrahamCampbell\ResultType\Result $f 47 | * 48 | * @return \GrahamCampbell\ResultType\Result 49 | */ 50 | abstract public function flatMap(callable $f); 51 | 52 | /** 53 | * Get the error option value. 54 | * 55 | * @return \PhpOption\Option 56 | */ 57 | abstract public function error(); 58 | 59 | /** 60 | * Map over the error value. 61 | * 62 | * @template F 63 | * 64 | * @param callable(E):F $f 65 | * 66 | * @return \GrahamCampbell\ResultType\Result 67 | */ 68 | abstract public function mapError(callable $f); 69 | } 70 | -------------------------------------------------------------------------------- /vendor/graham-campbell/result-type/src/Success.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | 14 | namespace GrahamCampbell\ResultType; 15 | 16 | use PhpOption\None; 17 | use PhpOption\Some; 18 | 19 | /** 20 | * @template T 21 | * @template E 22 | * @extends \GrahamCampbell\ResultType\Result 23 | */ 24 | final class Success extends Result 25 | { 26 | /** 27 | * @var T 28 | */ 29 | private $value; 30 | 31 | /** 32 | * Internal constructor for a success value. 33 | * 34 | * @param T $value 35 | * 36 | * @return void 37 | */ 38 | private function __construct($value) 39 | { 40 | $this->value = $value; 41 | } 42 | 43 | /** 44 | * Create a new error value. 45 | * 46 | * @template S 47 | * 48 | * @param S $value 49 | * 50 | * @return \GrahamCampbell\ResultType\Result 51 | */ 52 | public static function create($value) 53 | { 54 | return new self($value); 55 | } 56 | 57 | /** 58 | * Get the success option value. 59 | * 60 | * @return \PhpOption\Option 61 | */ 62 | public function success() 63 | { 64 | return Some::create($this->value); 65 | } 66 | 67 | /** 68 | * Map over the success value. 69 | * 70 | * @template S 71 | * 72 | * @param callable(T):S $f 73 | * 74 | * @return \GrahamCampbell\ResultType\Result 75 | */ 76 | public function map(callable $f) 77 | { 78 | return self::create($f($this->value)); 79 | } 80 | 81 | /** 82 | * Flat map over the success value. 83 | * 84 | * @template S 85 | * @template F 86 | * 87 | * @param callable(T):\GrahamCampbell\ResultType\Result $f 88 | * 89 | * @return \GrahamCampbell\ResultType\Result 90 | */ 91 | public function flatMap(callable $f) 92 | { 93 | return $f($this->value); 94 | } 95 | 96 | /** 97 | * Get the error option value. 98 | * 99 | * @return \PhpOption\Option 100 | */ 101 | public function error() 102 | { 103 | return None::create(); 104 | } 105 | 106 | /** 107 | * Map over the error value. 108 | * 109 | * @template F 110 | * 111 | * @param callable(E):F $f 112 | * 113 | * @return \GrahamCampbell\ResultType\Result 114 | */ 115 | public function mapError(callable $f) 116 | { 117 | return self::create($this->value); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | ## Issues 4 | Please submit all your bug reports, feature requests and pull requests here but note that this isn't the place for support requests. Please use [Stack Overflow](http://stackoverflow.com/) for this. 5 | 6 | ## Bug reports 7 | 1. Search the issues, has it already been reported? 8 | 2. Download the latest source, did this solve the problem? 9 | 4. If the answer to all of the above questions are "No" then open a bug report and include the following: 10 | * A short, descriptive title. 11 | * A summary of the problem. 12 | * The steps to reproduce the problem. 13 | * Possible solutions or other relevant information/suggestions. 14 | 15 | ## New features 16 | If you have an idea for a new feature, please file an issue first to see if it fits the scope of this project. That way no one's time needs to be wasted. 17 | 18 | ## Coding Guidelines 19 | We follow the coding standards outlined in [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) and [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). Please follow these guidelines when committing new code. 20 | 21 | In addition to the PSR guidelines we try to adhere to the following points: 22 | * We order all methods by visibility and then alphabetically, `private`/`protected` methods first and then `public`. For example: 23 | 24 | ``` 25 | protected function b() {} 26 | 27 | public function a() {} 28 | ``` 29 | 30 | instead of 31 | 32 | ``` 33 | public function a() {} 34 | 35 | protected function b() {} 36 | ``` 37 | 38 | * We strive to keep the inline documentation language consistent, take a look at existing docs for examples. 39 | 40 | Before committing any code, be sure to run `composer test` to ensure that the code style is consistent and all the tests pass. 41 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Jonathan Wilsson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/README.md: -------------------------------------------------------------------------------- 1 | # Spotify Web API PHP 2 | 3 | [![Packagist](https://img.shields.io/packagist/v/jwilsson/spotify-web-api-php.svg)](https://packagist.org/packages/jwilsson/spotify-web-api-php) 4 | [![Build Status](https://travis-ci.org/jwilsson/spotify-web-api-php.svg?branch=master)](https://travis-ci.org/jwilsson/spotify-web-api-php) 5 | [![Coverage Status](https://coveralls.io/repos/jwilsson/spotify-web-api-php/badge.svg?branch=master)](https://coveralls.io/r/jwilsson/spotify-web-api-php?branch=master) 6 | 7 | This is a PHP wrapper for [Spotify's Web API](https://developer.spotify.com/web-api/). It includes the following: 8 | 9 | * Helper methods for all API endpoints: 10 | * Information about artists, albums, tracks, and users. 11 | * List music featured by Spotify. 12 | * Playlist and user music library management. 13 | * Spotify catalog search. 14 | * User playback control. 15 | * Authorization flow helpers. 16 | * PSR-4 autoloading support. 17 | 18 | ## Requirements 19 | * PHP 5.6 or later. 20 | * PHP [cURL extension](http://php.net/manual/en/book.curl.php) (Usually included with PHP). 21 | 22 | ## Installation 23 | Install it using [Composer](https://getcomposer.org/): 24 | 25 | ```sh 26 | composer require jwilsson/spotify-web-api-php 27 | ``` 28 | 29 | ## Usage 30 | Before using the Spotify Web API, you'll need to create an app at [Spotify’s developer site](https://developer.spotify.com/web-api/). 31 | 32 | Simple example displaying a user's profile: 33 | ```php 34 | require 'vendor/autoload.php'; 35 | 36 | $session = new SpotifyWebAPI\Session( 37 | 'CLIENT_ID', 38 | 'CLIENT_SECRET', 39 | 'REDIRECT_URI' 40 | ); 41 | 42 | $api = new SpotifyWebAPI\SpotifyWebAPI(); 43 | 44 | if (isset($_GET['code'])) { 45 | $session->requestAccessToken($_GET['code']); 46 | $api->setAccessToken($session->getAccessToken()); 47 | 48 | print_r($api->me()); 49 | } else { 50 | $options = [ 51 | 'scope' => [ 52 | 'user-read-email', 53 | ], 54 | ]; 55 | 56 | header('Location: ' . $session->getAuthorizeUrl($options)); 57 | die(); 58 | } 59 | ``` 60 | 61 | For more instructions and examples, check out the [documentation](/docs/). 62 | 63 | The [Spotify Web API Console](https://developer.spotify.com/web-api/console/) can also be of great help when trying out the API. 64 | 65 | ## Contributing 66 | Contributions are more than welcome! See [CONTRIBUTING.md](/CONTRIBUTING.md) for more info. 67 | 68 | ## License 69 | MIT license. Please see [LICENSE.md](LICENSE.md) for more info. 70 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jwilsson/spotify-web-api-php", 3 | "description": "A PHP wrapper for Spotify's Web API.", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": ["spotify"], 7 | "homepage": "http://jwilsson.github.io/spotify-web-api-php/", 8 | "authors": [ 9 | { 10 | "name": "Jonathan Wilsson", 11 | "email": "jonathan.wilsson@gmail.com" 12 | } 13 | ], 14 | "require": { 15 | "php": "^5.6 || ^7.0", 16 | "ext-curl": "*" 17 | }, 18 | "require-dev": { 19 | "php-coveralls/php-coveralls": "^2.0", 20 | "phpunit/phpunit": "^5.7 || ^6.0", 21 | "squizlabs/php_codesniffer": "^3.0" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "SpotifyWebAPI\\": "src/" 26 | } 27 | }, 28 | "scripts": { 29 | "test": "phpcs src -v && phpunit" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/docs/README.md: -------------------------------------------------------------------------------- 1 | # Spotify Web API for PHP Documentation 2 | There are a lot of things possible with the Spotify Web API and these pages exist to give you an overview of how to make the most out of them. Which methods and options are available, how to use them, and what to do when something goes wrong. 3 | 4 | First, start by checking out the [Getting started guide](/docs/getting-started.md) before continuing with the examples below. 5 | 6 | ## Examples 7 | * **Authorization** 8 | * [Obtaining an access token using the Authorization Code Flow](/docs/examples/access-token-with-authorization-code-flow.md) 9 | * [Obtaining an access token using the Client Credentials Flow](/docs/examples/access-token-with-client-credentials-flow.md) 10 | * [Working with scopes](/docs/examples/working-with-scopes.md) 11 | * **Fetching data** 12 | * [Fetching catalog information](/docs/examples/fetching-catalog-information.md) 13 | * [Fetching Spotify featured content](/docs/examples/fetching-spotify-featured-content.md) 14 | * [Searching the Spotify catalog](/docs/examples/searching-the-spotify-catalog.md) 15 | * **Managing users** 16 | * [Controlling user playback](/docs/examples/controlling-user-playback.md) 17 | * [Following artists, playlists, and users](/docs/examples/following-artists-playlists-and-users.md) 18 | * [Managing a user's library](/docs/examples/managing-user-library.md) 19 | * [Managing a user's playlists](/docs/examples/managing-user-playlists.md) 20 | * [Managing a user's profile](/docs/examples/managing-user-profiles.md) 21 | * **Working with the API** 22 | * [Changing return type](/docs/examples/changing-return-type.md) 23 | * [Handling errors](/docs/examples/handling-errors.md) 24 | 25 | ## Method Reference 26 | A full method reference listing all public methods is [available here](/docs/method-reference/). 27 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/phpunit.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 18 | ./tests/ 19 | 20 | 21 | 22 | 23 | 24 | ./src/ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /vendor/jwilsson/spotify-web-api-php/src/SpotifyWebAPIAuthException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | namespace PhpOption; 20 | 21 | use EmptyIterator; 22 | 23 | /** 24 | * @extends Option 25 | */ 26 | final class None extends Option 27 | { 28 | /** @var None|null */ 29 | private static $instance; 30 | 31 | /** 32 | * @return None 33 | */ 34 | public static function create(): self 35 | { 36 | if (null === self::$instance) { 37 | self::$instance = new self(); 38 | } 39 | 40 | return self::$instance; 41 | } 42 | 43 | public function get() 44 | { 45 | throw new \RuntimeException('None has no value.'); 46 | } 47 | 48 | public function getOrCall($callable) 49 | { 50 | return $callable(); 51 | } 52 | 53 | public function getOrElse($default) 54 | { 55 | return $default; 56 | } 57 | 58 | public function getOrThrow(\Exception $ex) 59 | { 60 | throw $ex; 61 | } 62 | 63 | public function isEmpty(): bool 64 | { 65 | return true; 66 | } 67 | 68 | public function isDefined(): bool 69 | { 70 | return false; 71 | } 72 | 73 | public function orElse(Option $else) 74 | { 75 | return $else; 76 | } 77 | 78 | public function ifDefined($callable) 79 | { 80 | // Just do nothing in that case. 81 | } 82 | 83 | public function forAll($callable) 84 | { 85 | return $this; 86 | } 87 | 88 | public function map($callable) 89 | { 90 | return $this; 91 | } 92 | 93 | public function flatMap($callable) 94 | { 95 | return $this; 96 | } 97 | 98 | public function filter($callable) 99 | { 100 | return $this; 101 | } 102 | 103 | public function filterNot($callable) 104 | { 105 | return $this; 106 | } 107 | 108 | public function select($value) 109 | { 110 | return $this; 111 | } 112 | 113 | public function reject($value) 114 | { 115 | return $this; 116 | } 117 | 118 | public function getIterator(): EmptyIterator 119 | { 120 | return new EmptyIterator(); 121 | } 122 | 123 | public function foldLeft($initialValue, $callable) 124 | { 125 | return $initialValue; 126 | } 127 | 128 | public function foldRight($initialValue, $callable) 129 | { 130 | return $initialValue; 131 | } 132 | 133 | private function __construct() 134 | { 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /vendor/phpoption/phpoption/src/PhpOption/Some.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | namespace PhpOption; 20 | 21 | use ArrayIterator; 22 | 23 | /** 24 | * @template T 25 | * 26 | * @extends Option 27 | */ 28 | final class Some extends Option 29 | { 30 | /** @var T */ 31 | private $value; 32 | 33 | /** 34 | * @param T $value 35 | */ 36 | public function __construct($value) 37 | { 38 | $this->value = $value; 39 | } 40 | 41 | /** 42 | * @template U 43 | * 44 | * @param U $value 45 | * 46 | * @return Some 47 | */ 48 | public static function create($value): self 49 | { 50 | return new self($value); 51 | } 52 | 53 | public function isDefined(): bool 54 | { 55 | return true; 56 | } 57 | 58 | public function isEmpty(): bool 59 | { 60 | return false; 61 | } 62 | 63 | public function get() 64 | { 65 | return $this->value; 66 | } 67 | 68 | public function getOrElse($default) 69 | { 70 | return $this->value; 71 | } 72 | 73 | public function getOrCall($callable) 74 | { 75 | return $this->value; 76 | } 77 | 78 | public function getOrThrow(\Exception $ex) 79 | { 80 | return $this->value; 81 | } 82 | 83 | public function orElse(Option $else) 84 | { 85 | return $this; 86 | } 87 | 88 | public function ifDefined($callable) 89 | { 90 | $this->forAll($callable); 91 | } 92 | 93 | public function forAll($callable) 94 | { 95 | $callable($this->value); 96 | 97 | return $this; 98 | } 99 | 100 | public function map($callable) 101 | { 102 | return new self($callable($this->value)); 103 | } 104 | 105 | public function flatMap($callable) 106 | { 107 | /** @var mixed */ 108 | $rs = $callable($this->value); 109 | if (!$rs instanceof Option) { 110 | throw new \RuntimeException('Callables passed to flatMap() must return an Option. Maybe you should use map() instead?'); 111 | } 112 | 113 | return $rs; 114 | } 115 | 116 | public function filter($callable) 117 | { 118 | if (true === $callable($this->value)) { 119 | return $this; 120 | } 121 | 122 | return None::create(); 123 | } 124 | 125 | public function filterNot($callable) 126 | { 127 | if (false === $callable($this->value)) { 128 | return $this; 129 | } 130 | 131 | return None::create(); 132 | } 133 | 134 | public function select($value) 135 | { 136 | if ($this->value === $value) { 137 | return $this; 138 | } 139 | 140 | return None::create(); 141 | } 142 | 143 | public function reject($value) 144 | { 145 | if ($this->value === $value) { 146 | return None::create(); 147 | } 148 | 149 | return $this; 150 | } 151 | 152 | public function getIterator(): ArrayIterator 153 | { 154 | return new ArrayIterator([$this->value]); 155 | } 156 | 157 | public function foldLeft($initialValue, $callable) 158 | { 159 | return $callable($initialValue, $this->value); 160 | } 161 | 162 | public function foldRight($initialValue, $callable) 163 | { 164 | return $callable($this->value, $initialValue); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-ctype/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2019 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-ctype/README.md: -------------------------------------------------------------------------------- 1 | Symfony Polyfill / Ctype 2 | ======================== 3 | 4 | This component provides `ctype_*` functions to users who run php versions without the ctype extension. 5 | 6 | More information can be found in the 7 | [main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). 8 | 9 | License 10 | ======= 11 | 12 | This library is released under the [MIT license](LICENSE). 13 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-ctype/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use Symfony\Polyfill\Ctype as p; 13 | 14 | if (\PHP_VERSION_ID >= 80000) { 15 | return require __DIR__.'/bootstrap80.php'; 16 | } 17 | 18 | if (!function_exists('ctype_alnum')) { 19 | function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } 20 | } 21 | if (!function_exists('ctype_alpha')) { 22 | function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } 23 | } 24 | if (!function_exists('ctype_cntrl')) { 25 | function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } 26 | } 27 | if (!function_exists('ctype_digit')) { 28 | function ctype_digit($text) { return p\Ctype::ctype_digit($text); } 29 | } 30 | if (!function_exists('ctype_graph')) { 31 | function ctype_graph($text) { return p\Ctype::ctype_graph($text); } 32 | } 33 | if (!function_exists('ctype_lower')) { 34 | function ctype_lower($text) { return p\Ctype::ctype_lower($text); } 35 | } 36 | if (!function_exists('ctype_print')) { 37 | function ctype_print($text) { return p\Ctype::ctype_print($text); } 38 | } 39 | if (!function_exists('ctype_punct')) { 40 | function ctype_punct($text) { return p\Ctype::ctype_punct($text); } 41 | } 42 | if (!function_exists('ctype_space')) { 43 | function ctype_space($text) { return p\Ctype::ctype_space($text); } 44 | } 45 | if (!function_exists('ctype_upper')) { 46 | function ctype_upper($text) { return p\Ctype::ctype_upper($text); } 47 | } 48 | if (!function_exists('ctype_xdigit')) { 49 | function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } 50 | } 51 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-ctype/bootstrap80.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use Symfony\Polyfill\Ctype as p; 13 | 14 | if (!function_exists('ctype_alnum')) { 15 | function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); } 16 | } 17 | if (!function_exists('ctype_alpha')) { 18 | function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); } 19 | } 20 | if (!function_exists('ctype_cntrl')) { 21 | function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); } 22 | } 23 | if (!function_exists('ctype_digit')) { 24 | function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); } 25 | } 26 | if (!function_exists('ctype_graph')) { 27 | function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); } 28 | } 29 | if (!function_exists('ctype_lower')) { 30 | function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); } 31 | } 32 | if (!function_exists('ctype_print')) { 33 | function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); } 34 | } 35 | if (!function_exists('ctype_punct')) { 36 | function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); } 37 | } 38 | if (!function_exists('ctype_space')) { 39 | function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); } 40 | } 41 | if (!function_exists('ctype_upper')) { 42 | function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); } 43 | } 44 | if (!function_exists('ctype_xdigit')) { 45 | function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); } 46 | } 47 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-ctype/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/polyfill-ctype", 3 | "type": "library", 4 | "description": "Symfony polyfill for ctype functions", 5 | "keywords": ["polyfill", "compatibility", "portable", "ctype"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Gert de Pagter", 11 | "email": "BackEndTea@gmail.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=7.1" 20 | }, 21 | "autoload": { 22 | "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, 23 | "files": [ "bootstrap.php" ] 24 | }, 25 | "suggest": { 26 | "ext-ctype": "For best performance" 27 | }, 28 | "minimum-stability": "dev", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-main": "1.23-dev" 32 | }, 33 | "thanks": { 34 | "name": "symfony/polyfill", 35 | "url": "https://github.com/symfony/polyfill" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-mbstring/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2019 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-mbstring/README.md: -------------------------------------------------------------------------------- 1 | Symfony Polyfill / Mbstring 2 | =========================== 3 | 4 | This component provides a partial, native PHP implementation for the 5 | [Mbstring](https://php.net/mbstring) extension. 6 | 7 | More information can be found in the 8 | [main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). 9 | 10 | License 11 | ======= 12 | 13 | This library is released under the [MIT license](LICENSE). 14 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-mbstring/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/polyfill-mbstring", 3 | "type": "library", 4 | "description": "Symfony polyfill for the Mbstring extension", 5 | "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Nicolas Grekas", 11 | "email": "p@tchwork.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=7.1" 20 | }, 21 | "autoload": { 22 | "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, 23 | "files": [ "bootstrap.php" ] 24 | }, 25 | "suggest": { 26 | "ext-mbstring": "For best performance" 27 | }, 28 | "minimum-stability": "dev", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-main": "1.23-dev" 32 | }, 33 | "thanks": { 34 | "name": "symfony/polyfill", 35 | "url": "https://github.com/symfony/polyfill" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/Php80.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Polyfill\Php80; 13 | 14 | /** 15 | * @author Ion Bazan 16 | * @author Nico Oelgart 17 | * @author Nicolas Grekas 18 | * 19 | * @internal 20 | */ 21 | final class Php80 22 | { 23 | public static function fdiv(float $dividend, float $divisor): float 24 | { 25 | return @($dividend / $divisor); 26 | } 27 | 28 | public static function get_debug_type($value): string 29 | { 30 | switch (true) { 31 | case null === $value: return 'null'; 32 | case \is_bool($value): return 'bool'; 33 | case \is_string($value): return 'string'; 34 | case \is_array($value): return 'array'; 35 | case \is_int($value): return 'int'; 36 | case \is_float($value): return 'float'; 37 | case \is_object($value): break; 38 | case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; 39 | default: 40 | if (null === $type = @get_resource_type($value)) { 41 | return 'unknown'; 42 | } 43 | 44 | if ('Unknown' === $type) { 45 | $type = 'closed'; 46 | } 47 | 48 | return "resource ($type)"; 49 | } 50 | 51 | $class = \get_class($value); 52 | 53 | if (false === strpos($class, '@')) { 54 | return $class; 55 | } 56 | 57 | return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; 58 | } 59 | 60 | public static function get_resource_id($res): int 61 | { 62 | if (!\is_resource($res) && null === @get_resource_type($res)) { 63 | throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); 64 | } 65 | 66 | return (int) $res; 67 | } 68 | 69 | public static function preg_last_error_msg(): string 70 | { 71 | switch (preg_last_error()) { 72 | case \PREG_INTERNAL_ERROR: 73 | return 'Internal error'; 74 | case \PREG_BAD_UTF8_ERROR: 75 | return 'Malformed UTF-8 characters, possibly incorrectly encoded'; 76 | case \PREG_BAD_UTF8_OFFSET_ERROR: 77 | return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; 78 | case \PREG_BACKTRACK_LIMIT_ERROR: 79 | return 'Backtrack limit exhausted'; 80 | case \PREG_RECURSION_LIMIT_ERROR: 81 | return 'Recursion limit exhausted'; 82 | case \PREG_JIT_STACKLIMIT_ERROR: 83 | return 'JIT stack limit exhausted'; 84 | case \PREG_NO_ERROR: 85 | return 'No error'; 86 | default: 87 | return 'Unknown error'; 88 | } 89 | } 90 | 91 | public static function str_contains(string $haystack, string $needle): bool 92 | { 93 | return '' === $needle || false !== strpos($haystack, $needle); 94 | } 95 | 96 | public static function str_starts_with(string $haystack, string $needle): bool 97 | { 98 | return 0 === strncmp($haystack, $needle, \strlen($needle)); 99 | } 100 | 101 | public static function str_ends_with(string $haystack, string $needle): bool 102 | { 103 | return '' === $needle || ('' !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle))); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/README.md: -------------------------------------------------------------------------------- 1 | Symfony Polyfill / Php80 2 | ======================== 3 | 4 | This component provides features added to PHP 8.0 core: 5 | 6 | - `Stringable` interface 7 | - [`fdiv`](https://php.net/fdiv) 8 | - `ValueError` class 9 | - `UnhandledMatchError` class 10 | - `FILTER_VALIDATE_BOOL` constant 11 | - [`get_debug_type`](https://php.net/get_debug_type) 12 | - [`preg_last_error_msg`](https://php.net/preg_last_error_msg) 13 | - [`str_contains`](https://php.net/str_contains) 14 | - [`str_starts_with`](https://php.net/str_starts_with) 15 | - [`str_ends_with`](https://php.net/str_ends_with) 16 | - [`get_resource_id`](https://php.net/get_resource_id) 17 | 18 | More information can be found in the 19 | [main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). 20 | 21 | License 22 | ======= 23 | 24 | This library is released under the [MIT license](LICENSE). 25 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php: -------------------------------------------------------------------------------- 1 | flags = $flags; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use Symfony\Polyfill\Php80 as p; 13 | 14 | if (\PHP_VERSION_ID >= 80000) { 15 | return; 16 | } 17 | 18 | if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { 19 | define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); 20 | } 21 | 22 | if (!function_exists('fdiv')) { 23 | function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } 24 | } 25 | if (!function_exists('preg_last_error_msg')) { 26 | function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } 27 | } 28 | if (!function_exists('str_contains')) { 29 | function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } 30 | } 31 | if (!function_exists('str_starts_with')) { 32 | function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } 33 | } 34 | if (!function_exists('str_ends_with')) { 35 | function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } 36 | } 37 | if (!function_exists('get_debug_type')) { 38 | function get_debug_type($value): string { return p\Php80::get_debug_type($value); } 39 | } 40 | if (!function_exists('get_resource_id')) { 41 | function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/symfony/polyfill-php80/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/polyfill-php80", 3 | "type": "library", 4 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 5 | "keywords": ["polyfill", "shim", "compatibility", "portable"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Ion Bazan", 11 | "email": "ion.bazan@gmail.com" 12 | }, 13 | { 14 | "name": "Nicolas Grekas", 15 | "email": "p@tchwork.com" 16 | }, 17 | { 18 | "name": "Symfony Community", 19 | "homepage": "https://symfony.com/contributors" 20 | } 21 | ], 22 | "require": { 23 | "php": ">=7.1" 24 | }, 25 | "autoload": { 26 | "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, 27 | "files": [ "bootstrap.php" ], 28 | "classmap": [ "Resources/stubs" ] 29 | }, 30 | "minimum-stability": "dev", 31 | "extra": { 32 | "branch-alias": { 33 | "dev-main": "1.23-dev" 34 | }, 35 | "thanks": { 36 | "name": "symfony/polyfill", 37 | "url": "https://github.com/symfony/polyfill" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2014, Graham Campbell. 4 | Copyright (c) 2013, Vance Lucas. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vlucas/phpdotenv", 3 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", 4 | "keywords": ["env", "dotenv", "environment"], 5 | "license": "BSD-3-Clause", 6 | "authors": [ 7 | { 8 | "name": "Graham Campbell", 9 | "email": "graham@alt-three.com", 10 | "homepage": "https://gjcampbell.co.uk/" 11 | }, 12 | { 13 | "name": "Vance Lucas", 14 | "email": "vance@vancelucas.com", 15 | "homepage": "https://vancelucas.com/" 16 | } 17 | ], 18 | "require": { 19 | "php": "^7.1.3 || ^8.0", 20 | "ext-pcre": "*", 21 | "graham-campbell/result-type": "^1.0.1", 22 | "phpoption/phpoption": "^1.7.4", 23 | "symfony/polyfill-ctype": "^1.17", 24 | "symfony/polyfill-mbstring": "^1.17", 25 | "symfony/polyfill-php80": "^1.17" 26 | }, 27 | "require-dev": { 28 | "ext-filter": "*", 29 | "bamarni/composer-bin-plugin": "^1.4.1", 30 | "phpunit/phpunit": "^7.5.20 || ^8.5.14 || ^9.5.1" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "Dotenv\\": "src/" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "Dotenv\\Tests\\": "tests/Dotenv/" 40 | } 41 | }, 42 | "suggest": { 43 | "ext-filter": "Required to use the boolean validator." 44 | }, 45 | "config": { 46 | "preferred-install": "dist" 47 | }, 48 | "extra": { 49 | "branch-alias": { 50 | "dev-master": "5.3-dev" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | public function load(RepositoryInterface $repository, array $entries) 25 | { 26 | return \array_reduce($entries, static function (array $vars, Entry $entry) use ($repository) { 27 | $name = $entry->getName(); 28 | 29 | $value = $entry->getValue()->map(static function (Value $value) use ($repository) { 30 | return Resolver::resolve($repository, $value); 31 | }); 32 | 33 | if ($value->isDefined()) { 34 | $inner = $value->get(); 35 | if ($repository->set($name, $inner)) { 36 | return \array_merge($vars, [$name => $inner]); 37 | } 38 | } else { 39 | if ($repository->clear($name)) { 40 | return \array_merge($vars, [$name => null]); 41 | } 42 | } 43 | 44 | return $vars; 45 | }, []); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Loader/LoaderInterface.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | public function load(RepositoryInterface $repository, array $entries); 20 | } 21 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Loader/Resolver.php: -------------------------------------------------------------------------------- 1 | getVars(), static function (string $s, int $i) use ($repository) { 41 | return Str::substr($s, 0, $i).self::resolveVariable($repository, Str::substr($s, $i)); 42 | }, $value->getChars()); 43 | } 44 | 45 | /** 46 | * Resolve a single nested variable. 47 | * 48 | * @param \Dotenv\Repository\RepositoryInterface $repository 49 | * @param string $str 50 | * 51 | * @return string 52 | */ 53 | private static function resolveVariable(RepositoryInterface $repository, string $str) 54 | { 55 | return Regex::replaceCallback( 56 | '/\A\${([a-zA-Z0-9_.]+)}/', 57 | static function (array $matches) use ($repository) { 58 | return Option::fromValue($repository->get($matches[1])) 59 | ->getOrElse($matches[0]); 60 | }, 61 | $str, 62 | 1 63 | )->success()->getOrElse($str); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Parser/Entry.php: -------------------------------------------------------------------------------- 1 | name = $name; 36 | $this->value = $value; 37 | } 38 | 39 | /** 40 | * Get the entry name. 41 | * 42 | * @return string 43 | */ 44 | public function getName() 45 | { 46 | return $this->name; 47 | } 48 | 49 | /** 50 | * Get the entry value. 51 | * 52 | * @return \PhpOption\Option<\Dotenv\Parser\Value> 53 | */ 54 | public function getValue() 55 | { 56 | /** @var \PhpOption\Option<\Dotenv\Parser\Value> */ 57 | return Option::fromValue($this->value); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Parser/Lexer.php: -------------------------------------------------------------------------------- 1 | 39 | */ 40 | public static function lex(string $content) 41 | { 42 | static $regex; 43 | 44 | if ($regex === null) { 45 | $regex = '(('.\implode(')|(', self::PATTERNS).'))A'; 46 | } 47 | 48 | $tokens = []; 49 | 50 | $offset = 0; 51 | 52 | while (isset($content[$offset])) { 53 | if (!\preg_match($regex, $content, $matches, 0, $offset)) { 54 | throw new \Error(\sprintf('Lexer encountered unexpected character [%s].', $content[$offset])); 55 | } 56 | 57 | $offset += \strlen($matches[0]); 58 | 59 | yield $matches[0]; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Parser/Lines.php: -------------------------------------------------------------------------------- 1 | map(static function () use ($line) { 89 | return self::looksLikeMultilineStop($line, true) === false; 90 | })->getOrElse(false); 91 | } 92 | 93 | /** 94 | * Determine if the given line can be the start of a multiline variable. 95 | * 96 | * @param string $line 97 | * @param bool $started 98 | * 99 | * @return bool 100 | */ 101 | private static function looksLikeMultilineStop(string $line, bool $started) 102 | { 103 | if ($line === '"') { 104 | return true; 105 | } 106 | 107 | return Regex::occurences('/(?=([^\\\\]"))/', \str_replace('\\\\', '', $line))->map(static function (int $count) use ($started) { 108 | return $started ? $count > 1 : $count >= 1; 109 | })->success()->getOrElse(false); 110 | } 111 | 112 | /** 113 | * Determine if the line in the file is a comment or whitespace. 114 | * 115 | * @param string $line 116 | * 117 | * @return bool 118 | */ 119 | private static function isCommentOrWhitespace(string $line) 120 | { 121 | $line = \trim($line); 122 | 123 | return $line === '' || (isset($line[0]) && $line[0] === '#'); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Parser/Parser.php: -------------------------------------------------------------------------------- 1 | mapError(static function () { 26 | return 'Could not split into separate lines.'; 27 | })->flatMap(static function (array $lines) { 28 | return self::process(Lines::process($lines)); 29 | })->mapError(static function (string $error) { 30 | throw new InvalidFileException(\sprintf('Failed to parse dotenv file. %s', $error)); 31 | })->success()->get(); 32 | } 33 | 34 | /** 35 | * Convert the raw entries into proper entries. 36 | * 37 | * @param string[] $entries 38 | * 39 | * @return \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Entry[],string> 40 | */ 41 | private static function process(array $entries) 42 | { 43 | /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Entry[],string> */ 44 | return \array_reduce($entries, static function (Result $result, string $raw) { 45 | return $result->flatMap(static function (array $entries) use ($raw) { 46 | return EntryParser::parse($raw)->map(static function (Entry $entry) use ($entries) { 47 | return \array_merge($entries, [$entry]); 48 | }); 49 | }); 50 | }, Success::create([])); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Parser/ParserInterface.php: -------------------------------------------------------------------------------- 1 | chars = $chars; 36 | $this->vars = $vars; 37 | } 38 | 39 | /** 40 | * Create an empty value instance. 41 | * 42 | * @return \Dotenv\Parser\Value 43 | */ 44 | public static function blank() 45 | { 46 | return new self('', []); 47 | } 48 | 49 | /** 50 | * Create a new value instance, appending the characters. 51 | * 52 | * @param string $chars 53 | * @param bool $var 54 | * 55 | * @return \Dotenv\Parser\Value 56 | */ 57 | public function append(string $chars, bool $var) 58 | { 59 | return new self( 60 | $this->chars.$chars, 61 | $var ? \array_merge($this->vars, [Str::len($this->chars)]) : $this->vars 62 | ); 63 | } 64 | 65 | /** 66 | * Get the string representation of the parsed value. 67 | * 68 | * @return string 69 | */ 70 | public function getChars() 71 | { 72 | return $this->chars; 73 | } 74 | 75 | /** 76 | * Get the locations of the variables in the value. 77 | * 78 | * @return int[] 79 | */ 80 | public function getVars() 81 | { 82 | $vars = $this->vars; 83 | 84 | \rsort($vars); 85 | 86 | return $vars; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/AdapterInterface.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public static function create(); 15 | } 16 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ApacheAdapter.php: -------------------------------------------------------------------------------- 1 | 27 | */ 28 | public static function create() 29 | { 30 | if (self::isSupported()) { 31 | /** @var \PhpOption\Option */ 32 | return Some::create(new self()); 33 | } 34 | 35 | return None::create(); 36 | } 37 | 38 | /** 39 | * Determines if the adapter is supported. 40 | * 41 | * This happens if PHP is running as an Apache module. 42 | * 43 | * @return bool 44 | */ 45 | private static function isSupported() 46 | { 47 | return \function_exists('apache_getenv') && \function_exists('apache_setenv'); 48 | } 49 | 50 | /** 51 | * Read an environment variable, if it exists. 52 | * 53 | * @param string $name 54 | * 55 | * @return \PhpOption\Option 56 | */ 57 | public function read(string $name) 58 | { 59 | /** @var \PhpOption\Option */ 60 | return Option::fromValue(apache_getenv($name))->filter(static function ($value) { 61 | return \is_string($value) && $value !== ''; 62 | }); 63 | } 64 | 65 | /** 66 | * Write to an environment variable, if possible. 67 | * 68 | * @param string $name 69 | * @param string $value 70 | * 71 | * @return bool 72 | */ 73 | public function write(string $name, string $value) 74 | { 75 | return apache_setenv($name, $value); 76 | } 77 | 78 | /** 79 | * Delete an environment variable, if possible. 80 | * 81 | * @param string $name 82 | * 83 | * @return bool 84 | */ 85 | public function delete(string $name) 86 | { 87 | return apache_setenv($name, ''); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ArrayAdapter.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | private $variables; 18 | 19 | /** 20 | * Create a new array adapter instance. 21 | * 22 | * @return void 23 | */ 24 | private function __construct() 25 | { 26 | $this->variables = []; 27 | } 28 | 29 | /** 30 | * Create a new instance of the adapter, if it is available. 31 | * 32 | * @return \PhpOption\Option<\Dotenv\Repository\Adapter\AdapterInterface> 33 | */ 34 | public static function create() 35 | { 36 | /** @var \PhpOption\Option */ 37 | return Some::create(new self()); 38 | } 39 | 40 | /** 41 | * Read an environment variable, if it exists. 42 | * 43 | * @param string $name 44 | * 45 | * @return \PhpOption\Option 46 | */ 47 | public function read(string $name) 48 | { 49 | return Option::fromArraysValue($this->variables, $name); 50 | } 51 | 52 | /** 53 | * Write to an environment variable, if possible. 54 | * 55 | * @param string $name 56 | * @param string $value 57 | * 58 | * @return bool 59 | */ 60 | public function write(string $name, string $value) 61 | { 62 | $this->variables[$name] = $value; 63 | 64 | return true; 65 | } 66 | 67 | /** 68 | * Delete an environment variable, if possible. 69 | * 70 | * @param string $name 71 | * 72 | * @return bool 73 | */ 74 | public function delete(string $name) 75 | { 76 | unset($this->variables[$name]); 77 | 78 | return true; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/EnvConstAdapter.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public static function create() 28 | { 29 | /** @var \PhpOption\Option */ 30 | return Some::create(new self()); 31 | } 32 | 33 | /** 34 | * Read an environment variable, if it exists. 35 | * 36 | * @param string $name 37 | * 38 | * @return \PhpOption\Option 39 | */ 40 | public function read(string $name) 41 | { 42 | /** @var \PhpOption\Option */ 43 | return Option::fromArraysValue($_ENV, $name) 44 | ->map(static function ($value) { 45 | if ($value === false) { 46 | return 'false'; 47 | } 48 | 49 | if ($value === true) { 50 | return 'true'; 51 | } 52 | 53 | return $value; 54 | })->filter(static function ($value) { 55 | return \is_string($value); 56 | }); 57 | } 58 | 59 | /** 60 | * Write to an environment variable, if possible. 61 | * 62 | * @param string $name 63 | * @param string $value 64 | * 65 | * @return bool 66 | */ 67 | public function write(string $name, string $value) 68 | { 69 | $_ENV[$name] = $value; 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * Delete an environment variable, if possible. 76 | * 77 | * @param string $name 78 | * 79 | * @return bool 80 | */ 81 | public function delete(string $name) 82 | { 83 | unset($_ENV[$name]); 84 | 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/GuardedWriter.php: -------------------------------------------------------------------------------- 1 | writer = $writer; 34 | $this->allowList = $allowList; 35 | } 36 | 37 | /** 38 | * Write to an environment variable, if possible. 39 | * 40 | * @param string $name 41 | * @param string $value 42 | * 43 | * @return bool 44 | */ 45 | public function write(string $name, string $value) 46 | { 47 | // Don't set non-allowed variables 48 | if (!$this->isAllowed($name)) { 49 | return false; 50 | } 51 | 52 | // Set the value on the inner writer 53 | return $this->writer->write($name, $value); 54 | } 55 | 56 | /** 57 | * Delete an environment variable, if possible. 58 | * 59 | * @param string $name 60 | * 61 | * @return bool 62 | */ 63 | public function delete(string $name) 64 | { 65 | // Don't clear non-allowed variables 66 | if (!$this->isAllowed($name)) { 67 | return false; 68 | } 69 | 70 | // Set the value on the inner writer 71 | return $this->writer->delete($name); 72 | } 73 | 74 | /** 75 | * Determine if the given variable is allowed. 76 | * 77 | * @param string $name 78 | * 79 | * @return bool 80 | */ 81 | private function isAllowed(string $name) 82 | { 83 | return \in_array($name, $this->allowList, true); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ImmutableWriter.php: -------------------------------------------------------------------------------- 1 | 27 | */ 28 | private $loaded; 29 | 30 | /** 31 | * Create a new immutable writer instance. 32 | * 33 | * @param \Dotenv\Repository\Adapter\WriterInterface $writer 34 | * @param \Dotenv\Repository\Adapter\ReaderInterface $reader 35 | * 36 | * @return void 37 | */ 38 | public function __construct(WriterInterface $writer, ReaderInterface $reader) 39 | { 40 | $this->writer = $writer; 41 | $this->reader = $reader; 42 | $this->loaded = []; 43 | } 44 | 45 | /** 46 | * Write to an environment variable, if possible. 47 | * 48 | * @param string $name 49 | * @param string $value 50 | * 51 | * @return bool 52 | */ 53 | public function write(string $name, string $value) 54 | { 55 | // Don't overwrite existing environment variables 56 | // Ruby's dotenv does this with `ENV[key] ||= value` 57 | if ($this->isExternallyDefined($name)) { 58 | return false; 59 | } 60 | 61 | // Set the value on the inner writer 62 | if (!$this->writer->write($name, $value)) { 63 | return false; 64 | } 65 | 66 | // Record that we have loaded the variable 67 | $this->loaded[$name] = ''; 68 | 69 | return true; 70 | } 71 | 72 | /** 73 | * Delete an environment variable, if possible. 74 | * 75 | * @param string $name 76 | * 77 | * @return bool 78 | */ 79 | public function delete(string $name) 80 | { 81 | // Don't clear existing environment variables 82 | if ($this->isExternallyDefined($name)) { 83 | return false; 84 | } 85 | 86 | // Clear the value on the inner writer 87 | if (!$this->writer->delete($name)) { 88 | return false; 89 | } 90 | 91 | // Leave the variable as fair game 92 | unset($this->loaded[$name]); 93 | 94 | return true; 95 | } 96 | 97 | /** 98 | * Determine if the given variable is externally defined. 99 | * 100 | * That is, is it an "existing" variable. 101 | * 102 | * @param string $name 103 | * 104 | * @return bool 105 | */ 106 | private function isExternallyDefined(string $name) 107 | { 108 | return $this->reader->read($name)->isDefined() && !isset($this->loaded[$name]); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiReader.php: -------------------------------------------------------------------------------- 1 | readers = $readers; 28 | } 29 | 30 | /** 31 | * Read an environment variable, if it exists. 32 | * 33 | * @param string $name 34 | * 35 | * @return \PhpOption\Option 36 | */ 37 | public function read(string $name) 38 | { 39 | foreach ($this->readers as $reader) { 40 | $result = $reader->read($name); 41 | if ($result->isDefined()) { 42 | return $result; 43 | } 44 | } 45 | 46 | return None::create(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiWriter.php: -------------------------------------------------------------------------------- 1 | writers = $writers; 26 | } 27 | 28 | /** 29 | * Write to an environment variable, if possible. 30 | * 31 | * @param string $name 32 | * @param string $value 33 | * 34 | * @return bool 35 | */ 36 | public function write(string $name, string $value) 37 | { 38 | foreach ($this->writers as $writers) { 39 | if (!$writers->write($name, $value)) { 40 | return false; 41 | } 42 | } 43 | 44 | return true; 45 | } 46 | 47 | /** 48 | * Delete an environment variable, if possible. 49 | * 50 | * @param string $name 51 | * 52 | * @return bool 53 | */ 54 | public function delete(string $name) 55 | { 56 | foreach ($this->writers as $writers) { 57 | if (!$writers->delete($name)) { 58 | return false; 59 | } 60 | } 61 | 62 | return true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/PutenvAdapter.php: -------------------------------------------------------------------------------- 1 | 27 | */ 28 | public static function create() 29 | { 30 | if (self::isSupported()) { 31 | /** @var \PhpOption\Option */ 32 | return Some::create(new self()); 33 | } 34 | 35 | return None::create(); 36 | } 37 | 38 | /** 39 | * Determines if the adapter is supported. 40 | * 41 | * @return bool 42 | */ 43 | private static function isSupported() 44 | { 45 | return \function_exists('getenv') && \function_exists('putenv'); 46 | } 47 | 48 | /** 49 | * Read an environment variable, if it exists. 50 | * 51 | * @param string $name 52 | * 53 | * @return \PhpOption\Option 54 | */ 55 | public function read(string $name) 56 | { 57 | /** @var \PhpOption\Option */ 58 | return Option::fromValue(\getenv($name), false)->filter(static function ($value) { 59 | return \is_string($value); 60 | }); 61 | } 62 | 63 | /** 64 | * Write to an environment variable, if possible. 65 | * 66 | * @param string $name 67 | * @param string $value 68 | * 69 | * @return bool 70 | */ 71 | public function write(string $name, string $value) 72 | { 73 | \putenv("$name=$value"); 74 | 75 | return true; 76 | } 77 | 78 | /** 79 | * Delete an environment variable, if possible. 80 | * 81 | * @param string $name 82 | * 83 | * @return bool 84 | */ 85 | public function delete(string $name) 86 | { 87 | \putenv($name); 88 | 89 | return true; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ReaderInterface.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public function read(string $name); 17 | } 18 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ReplacingWriter.php: -------------------------------------------------------------------------------- 1 | 27 | */ 28 | private $seen; 29 | 30 | /** 31 | * Create a new replacement writer instance. 32 | * 33 | * @param \Dotenv\Repository\Adapter\WriterInterface $writer 34 | * @param \Dotenv\Repository\Adapter\ReaderInterface $reader 35 | * 36 | * @return void 37 | */ 38 | public function __construct(WriterInterface $writer, ReaderInterface $reader) 39 | { 40 | $this->writer = $writer; 41 | $this->reader = $reader; 42 | $this->seen = []; 43 | } 44 | 45 | /** 46 | * Write to an environment variable, if possible. 47 | * 48 | * @param string $name 49 | * @param string $value 50 | * 51 | * @return bool 52 | */ 53 | public function write(string $name, string $value) 54 | { 55 | if ($this->exists($name)) { 56 | return $this->writer->write($name, $value); 57 | } 58 | 59 | // succeed if nothing to do 60 | return true; 61 | } 62 | 63 | /** 64 | * Delete an environment variable, if possible. 65 | * 66 | * @param string $name 67 | * 68 | * @return bool 69 | */ 70 | public function delete(string $name) 71 | { 72 | if ($this->exists($name)) { 73 | return $this->writer->delete($name); 74 | } 75 | 76 | // succeed if nothing to do 77 | return true; 78 | } 79 | 80 | /** 81 | * Does the given environment variable exist. 82 | * 83 | * Returns true if it currently exists, or existed at any point in the past 84 | * that we are aware of. 85 | * 86 | * @param string $name 87 | * 88 | * @return bool 89 | */ 90 | private function exists(string $name) 91 | { 92 | if (isset($this->seen[$name])) { 93 | return true; 94 | } 95 | 96 | if ($this->reader->read($name)->isDefined()) { 97 | $this->seen[$name] = ''; 98 | 99 | return true; 100 | } 101 | 102 | return false; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/ServerConstAdapter.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public static function create() 28 | { 29 | /** @var \PhpOption\Option */ 30 | return Some::create(new self()); 31 | } 32 | 33 | /** 34 | * Read an environment variable, if it exists. 35 | * 36 | * @param string $name 37 | * 38 | * @return \PhpOption\Option 39 | */ 40 | public function read(string $name) 41 | { 42 | /** @var \PhpOption\Option */ 43 | return Option::fromArraysValue($_SERVER, $name) 44 | ->map(static function ($value) { 45 | if ($value === false) { 46 | return 'false'; 47 | } 48 | 49 | if ($value === true) { 50 | return 'true'; 51 | } 52 | 53 | return $value; 54 | })->filter(static function ($value) { 55 | return \is_string($value); 56 | }); 57 | } 58 | 59 | /** 60 | * Write to an environment variable, if possible. 61 | * 62 | * @param string $name 63 | * @param string $value 64 | * 65 | * @return bool 66 | */ 67 | public function write(string $name, string $value) 68 | { 69 | $_SERVER[$name] = $value; 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * Delete an environment variable, if possible. 76 | * 77 | * @param string $name 78 | * 79 | * @return bool 80 | */ 81 | public function delete(string $name) 82 | { 83 | unset($_SERVER[$name]); 84 | 85 | return true; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/Adapter/WriterInterface.php: -------------------------------------------------------------------------------- 1 | reader = $reader; 37 | $this->writer = $writer; 38 | } 39 | 40 | /** 41 | * Determine if the given environment variable is defined. 42 | * 43 | * @param string $name 44 | * 45 | * @return bool 46 | */ 47 | public function has(string $name) 48 | { 49 | return $this->reader->read($name)->isDefined(); 50 | } 51 | 52 | /** 53 | * Get an environment variable. 54 | * 55 | * @param string $name 56 | * 57 | * @return string|null 58 | */ 59 | public function get(string $name) 60 | { 61 | return $this->reader->read($name)->getOrElse(null); 62 | } 63 | 64 | /** 65 | * Set an environment variable. 66 | * 67 | * @param string $name 68 | * @param string $value 69 | * 70 | * @return bool 71 | */ 72 | public function set(string $name, string $value) 73 | { 74 | return $this->writer->write($name, $value); 75 | } 76 | 77 | /** 78 | * Clear an environment variable. 79 | * 80 | * @param string $name 81 | * 82 | * @return bool 83 | */ 84 | public function clear(string $name) 85 | { 86 | return $this->writer->delete($name); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Repository/RepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 42 | */ 43 | public static function read(array $filePaths, bool $shortCircuit = true, string $fileEncoding = null) 44 | { 45 | $output = []; 46 | 47 | foreach ($filePaths as $filePath) { 48 | $content = self::readFromFile($filePath, $fileEncoding); 49 | if ($content->isDefined()) { 50 | $output[$filePath] = $content->get(); 51 | if ($shortCircuit) { 52 | break; 53 | } 54 | } 55 | } 56 | 57 | return $output; 58 | } 59 | 60 | /** 61 | * Read the given file. 62 | * 63 | * @param string $path 64 | * @param string|null $encoding 65 | * 66 | * @throws \Dotenv\Exception\InvalidEncodingException 67 | * 68 | * @return \PhpOption\Option 69 | */ 70 | private static function readFromFile(string $path, string $encoding = null) 71 | { 72 | /** @var Option */ 73 | $content = Option::fromValue(@\file_get_contents($path), false); 74 | 75 | return $content->flatMap(static function (string $content) use ($encoding) { 76 | return Str::utf8($content, $encoding)->mapError(static function (string $error) { 77 | throw new InvalidEncodingException($error); 78 | })->success(); 79 | }); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Store/FileStore.php: -------------------------------------------------------------------------------- 1 | filePaths = $filePaths; 45 | $this->shortCircuit = $shortCircuit; 46 | $this->fileEncoding = $fileEncoding; 47 | } 48 | 49 | /** 50 | * Read the content of the environment file(s). 51 | * 52 | * @throws \Dotenv\Exception\InvalidEncodingException|\Dotenv\Exception\InvalidPathException 53 | * 54 | * @return string 55 | */ 56 | public function read() 57 | { 58 | if ($this->filePaths === []) { 59 | throw new InvalidPathException('At least one environment file path must be provided.'); 60 | } 61 | 62 | $contents = Reader::read($this->filePaths, $this->shortCircuit, $this->fileEncoding); 63 | 64 | if (\count($contents) > 0) { 65 | return \implode("\n", $contents); 66 | } 67 | 68 | throw new InvalidPathException( 69 | \sprintf('Unable to read any of the environment file(s) at [%s].', \implode(', ', $this->filePaths)) 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Store/StoreBuilder.php: -------------------------------------------------------------------------------- 1 | paths = $paths; 59 | $this->names = $names; 60 | $this->shortCircuit = $shortCircuit; 61 | $this->fileEncoding = $fileEncoding; 62 | } 63 | 64 | /** 65 | * Create a new store builder instance with no names. 66 | * 67 | * @return \Dotenv\Store\StoreBuilder 68 | */ 69 | public static function createWithNoNames() 70 | { 71 | return new self(); 72 | } 73 | 74 | /** 75 | * Create a new store builder instance with the default name. 76 | * 77 | * @return \Dotenv\Store\StoreBuilder 78 | */ 79 | public static function createWithDefaultName() 80 | { 81 | return new self([], [self::DEFAULT_NAME]); 82 | } 83 | 84 | /** 85 | * Creates a store builder with the given path added. 86 | * 87 | * @param string $path 88 | * 89 | * @return \Dotenv\Store\StoreBuilder 90 | */ 91 | public function addPath(string $path) 92 | { 93 | return new self(\array_merge($this->paths, [$path]), $this->names, $this->shortCircuit, $this->fileEncoding); 94 | } 95 | 96 | /** 97 | * Creates a store builder with the given name added. 98 | * 99 | * @param string $name 100 | * 101 | * @return \Dotenv\Store\StoreBuilder 102 | */ 103 | public function addName(string $name) 104 | { 105 | return new self($this->paths, \array_merge($this->names, [$name]), $this->shortCircuit, $this->fileEncoding); 106 | } 107 | 108 | /** 109 | * Creates a store builder with short circuit mode enabled. 110 | * 111 | * @return \Dotenv\Store\StoreBuilder 112 | */ 113 | public function shortCircuit() 114 | { 115 | return new self($this->paths, $this->names, true, $this->fileEncoding); 116 | } 117 | 118 | /** 119 | * Creates a store builder with the specified file encoding. 120 | * 121 | * @param string|null $fileEncoding 122 | * 123 | * @return \Dotenv\Store\StoreBuilder 124 | */ 125 | public function fileEncoding(string $fileEncoding = null) 126 | { 127 | return new self($this->paths, $this->names, $this->shortCircuit, $fileEncoding); 128 | } 129 | 130 | /** 131 | * Creates a new store instance. 132 | * 133 | * @return \Dotenv\Store\StoreInterface 134 | */ 135 | public function make() 136 | { 137 | return new FileStore( 138 | Paths::filePaths($this->paths, $this->names), 139 | $this->shortCircuit, 140 | $this->fileEncoding 141 | ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Store/StoreInterface.php: -------------------------------------------------------------------------------- 1 | content = $content; 26 | } 27 | 28 | /** 29 | * Read the content of the environment file(s). 30 | * 31 | * @return string 32 | */ 33 | public function read() 34 | { 35 | return $this->content; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Util/Regex.php: -------------------------------------------------------------------------------- 1 | 34 | */ 35 | public static function matches(string $pattern, string $subject) 36 | { 37 | return self::pregAndWrap(static function (string $subject) use ($pattern) { 38 | return @\preg_match($pattern, $subject) === 1; 39 | }, $subject); 40 | } 41 | 42 | /** 43 | * Perform a preg match all, wrapping up the result. 44 | * 45 | * @param string $pattern 46 | * @param string $subject 47 | * 48 | * @return \GrahamCampbell\ResultType\Result 49 | */ 50 | public static function occurences(string $pattern, string $subject) 51 | { 52 | return self::pregAndWrap(static function (string $subject) use ($pattern) { 53 | return (int) @\preg_match_all($pattern, $subject); 54 | }, $subject); 55 | } 56 | 57 | /** 58 | * Perform a preg replace callback, wrapping up the result. 59 | * 60 | * @param string $pattern 61 | * @param callable $callback 62 | * @param string $subject 63 | * @param int|null $limit 64 | * 65 | * @return \GrahamCampbell\ResultType\Result 66 | */ 67 | public static function replaceCallback(string $pattern, callable $callback, string $subject, int $limit = null) 68 | { 69 | return self::pregAndWrap(static function (string $subject) use ($pattern, $callback, $limit) { 70 | return (string) @\preg_replace_callback($pattern, $callback, $subject, $limit ?? -1); 71 | }, $subject); 72 | } 73 | 74 | /** 75 | * Perform a preg split, wrapping up the result. 76 | * 77 | * @param string $pattern 78 | * @param string $subject 79 | * 80 | * @return \GrahamCampbell\ResultType\Result 81 | */ 82 | public static function split(string $pattern, string $subject) 83 | { 84 | return self::pregAndWrap(static function (string $subject) use ($pattern) { 85 | /** @var string[] */ 86 | return (array) @\preg_split($pattern, $subject); 87 | }, $subject); 88 | } 89 | 90 | /** 91 | * Perform a preg operation, wrapping up the result. 92 | * 93 | * @template V 94 | * 95 | * @param callable(string):V $operation 96 | * @param string $subject 97 | * 98 | * @return \GrahamCampbell\ResultType\Result 99 | */ 100 | private static function pregAndWrap(callable $operation, string $subject) 101 | { 102 | $result = $operation($subject); 103 | 104 | if (\preg_last_error() !== \PREG_NO_ERROR) { 105 | return Error::create(\preg_last_error_msg()); 106 | } 107 | 108 | return Success::create($result); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /vendor/vlucas/phpdotenv/src/Util/Str.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | public static function utf8(string $input, string $encoding = null) 37 | { 38 | if ($encoding !== null && !\in_array($encoding, \mb_list_encodings(), true)) { 39 | /** @var \GrahamCampbell\ResultType\Result */ 40 | return Error::create( 41 | \sprintf('Illegal character encoding [%s] specified.', $encoding) 42 | ); 43 | } 44 | 45 | /** @var \GrahamCampbell\ResultType\Result */ 46 | return Success::create( 47 | $encoding === null ? @\mb_convert_encoding($input, 'UTF-8') : @\mb_convert_encoding($input, 'UTF-8', $encoding) 48 | ); 49 | } 50 | 51 | /** 52 | * Search for a given substring of the input. 53 | * 54 | * @param string $haystack 55 | * @param string $needle 56 | * 57 | * @return \PhpOption\Option 58 | */ 59 | public static function pos(string $haystack, string $needle) 60 | { 61 | /** @var \PhpOption\Option */ 62 | return Option::fromValue(\mb_strpos($haystack, $needle, 0, 'UTF-8'), false); 63 | } 64 | 65 | /** 66 | * Grab the specified substring of the input. 67 | * 68 | * @param string $input 69 | * @param int $start 70 | * @param int|null $length 71 | * 72 | * @return string 73 | */ 74 | public static function substr(string $input, int $start, int $length = null) 75 | { 76 | return \mb_substr($input, $start, $length, 'UTF-8'); 77 | } 78 | 79 | /** 80 | * Compute the length of the given string. 81 | * 82 | * @param string $input 83 | * 84 | * @return int 85 | */ 86 | public static function len(string $input) 87 | { 88 | return \mb_strlen($input, 'UTF-8'); 89 | } 90 | } 91 | --------------------------------------------------------------------------------