NGINX dynamic location to create dynamic og:image - html

I developed a site that shows some products from a store. The site URL looks like that:
http://testsite.com
The site has the functionality of sharing the product (it's already working) generating a link that can be shared at facebook or WhatsApp or anywhere. The link of the shared product is:
http://testsite.com/product/1234
Where 1234 is the product ID. All the products have images with the ID name. Ex: 1234.jpg. The link for the image of the product ID 1234 is:
http://testsite.com/static/imgs/1234.jpg
This site is hosted using a simple NGINX server, that just provides the files.
At the head of my index.html file I have a default og:image for sharing:
<meta property="og:image" content="http://testsite.com/static/imgs/main.jpg">
I wanna the NGINX server to replace this default og:image by the shared ID image. I already know how to do that at NGINX. At the NGINX configuration file (/etc/nginx/conf.d/default.conf) I used the sub_filter option. My NGINX configuration file is:
server {
listen 80;
server_name *.testsite.com;
root /var/www/testsite.com/dist;
location / {
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location ~ /product/(.*) {
index index.html index.htm;
try_files $uri $uri/ /index.html;
sub_filter 'http://testsite.com/static/imgs/main.jpg'
'http://testsite.com/static/imgs/$1.jpg';
sub_filter_once on;
}
}
This configuration is working for the location /, but for the location ~ /product/(.*) it is not working.
When I test the sub_fiter option at the location / using any other image it replaces correctly.
QUESTIONS:
1) How can I get the product ID (1234) from the URL (http://testsite.com/product/1234)? $1 is not working.
2) I think that when entering at the location ~ /product/(.*), it also redirects for the location /. How can I fix this configuration file to works as expected?

I think your alias statement is the problem.
Reading in nginx docs:
location /i/ {
alias /data/w3/images/;
}
on request of “/i/top.gif”, the file /data/w3/images/top.gif will be sent.
It means that in your case on each ~/product/(.*) request /var/www/testsite.com/dist/index.html will be sent without taking product ID into account. You might want to configure alias on / to avoid that. This is also likely to be the reason you get "redirected" to /.
As for $1, it should work as you have it now. When you fix the alias, I think it will work then. If not, you can try the named match: (?<product>[0-9]+) instead of (.*), then you can use the $product variable to reference the id.
There's another small glitch in your code — you're adding extra quote marks on replace. The second argument to sub_filter is in quotes twice.
Working Example
UPDATE: Ok, I got it working on localhost with the following nginx config (testing on "Hello World"):
location ~ /product/(\d+)$ {
set $product $1;
try_files $uri $uri/ /index.html;
}
location / {
if ( $product = '' ) {
set $search 'Non-Existent-String';
}
if ( $product != '' ) {
set $search 'World'; # the string you want to replace
}
index index.html index.htm;
sub_filter '$search' 'Product #$product';
}
The key here is that when you use try_files, it does get to location /. So we need to sub_filter in /. We also don't want to sub_filter regular /index.html requests. Something like if ($product) sub_filter would be nice, but is impossible with nginx. So I just leave sub_filter but only set real search string for product requests.

Related

Uploading a file into a subdirectory of a Team Drive

How may I successfully upload a file to a sub-directory of our team drive? Using the drive_find() identifies items in my directory. No matter what I try, the best I can do is get the files to land in the team drive 'root' directory.
I successfully get a list of names, id's and drive resources from this:
drive_find(team_drive = 'Data Analytics Team')
like so:
# A tibble: 29 x 3
name id drive_resource
* <chr> <chr> <list>
1 00.ExampleSubDirectory 1XoNCDizzZMHZ4sbBhnCXb-qokk8TW7Q_ <list [30]>
2 df_iris_in-2019-05-01 1kXSD_t96roqeLuXb0BDJfpCejlyZCa6FSL2YtdeWtxE <list [33]>
3 df_iris_in-2019-05-01 1qT_kRff8J8Qu5ZLxZhGLMDB7gO9O1PTtJ_KHsjItgFI <list [33]>
When I attempt to use the example sub-directory id like so:
td <- team_drive_get(as_id("1XoNCDizzZMHZ4sbBhnCXb-qokk8TW7Q_"))
All I get is this error:
Error: HTTP error [404] Shared drive not found: 1XoNCDizzZMHZ4sbBhnCXb-qokk8TW7Q_
* domain: global
* reason: notFound
* message: Shared drive not found: 1XoNCDizzZMHZ4sbBhnCXb-qokk8TW7Q_
* locationType: parameter
* location: driveId
I get the same results using the url, or the resource id. I have tried everything in the docs here: https://googledrive.tidyverse.org/
https://cran.r-project.org/web/packages/googledrive/googledrive.pdf
How can I specify a path to a subdirectory inside my team drive?
Find the id of the folder you want to write to. It is easiest to navigate to it in the browser. The id is located in the URL.
For example it is 1v4SQb39RTE0MCzrZlLXzxVDB4HPZ8NK7 in this URL: https://drive.google.com/drive/u/0/folders/1v4SQb39RTE0MCzrZlLXzxVDB4HPZ8NK7
Stuff that ID into a googsdrive connecting drive path/socket.
drivepath <- drive_get(as_id("1v4SQb39RTE0MCzrZlLXzxVDB4HPZ8NK7"))
Write your file to csv, being sure to name the csv what you want the spreadsheet to get labelled (minus the .csv extension). (You can do this in a tempfile but then your googlespreadsheet will end up with the tempfile's name.)
write_csv(iris, 'iris_example.csv')
Finally push the file up to your desired directory.
drive_upload('iris_example.csv', type='spreadsheet', path = drivepath)

Jekyll Filename Without Date

I want to build documentation site using Jekyll and GitHub Pages. The problem is Jekyll only accept a filename under _posts with exact pattern like YYYY-MM-DD-your-title-is-here.md.
How can I post a page in Jekyll without this filename pattern? Something like:
awesome-title.md
yet-another-title.md
etc.md
Thanks for your advance.
Don't use posts; posts are things with dates. Sounds like you probably want to use collections instead; you get all the power of Posts; but without the pesky date / naming requirements.
https://jekyllrb.com/docs/collections/
I use collections for almost everything that isn't a post. This is how my own site is configured to use collections for 'pages' as well as more specific sections of my site:
I guess that you are annoyed with the post url http://domaine.tld/category/2014/11/22/post.html.
You cannot bypass the filename pattern for posts, but you can use permalink (see documentation).
_posts/2014-11-22-other-post.md
---
title: "Other post"
date: 2014-11-22 09:49:00
permalink: anything-you-want
---
File will be anything-you-want/index.html.
Url will be http://domaine.tld/anything-you-want.
What I did without "abandoning" the posts (looks like using collections or pages is a better and deeper solution) is a combination of what #igneousaur says in a comment plus using the same date as prefix of file names:
Use permalink: /:title.html in _config.yml (no dates in published URLs).
Use the format 0001-01-01-name.md for all files in _posts folder (jekyll is happy about the file names and I'm happy about the sorting of the files).
Of course, we can include any "extra information" on the name, maybe some incremental id o anything that help us to organize the files, e.g.: 0001-01-01-001-name.md.
The way I solved it was by adding _plugins/no_date.rb:
class Jekyll::PostReader
# Don't use DATE_FILENAME_MATCHER so we don't need to put those stupid dates
# in the filename. Also limit to just *.markdown, so it won't process binary
# files from e.g. drags.
def read_posts(dir)
read_publishable(dir, "_posts", /.*\.markdown$/)
end
def read_drafts(dir)
read_publishable(dir, "_drafts", /.*\.markdown$/)
end
end
This overrides ("monkey patches") the standard Jekyll functions; the defaults for these are:
# Read all the files in <source>/<dir>/_drafts and create a new
# Document object with each one.
#
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_drafts(dir)
read_publishable(dir, "_drafts", Document::DATELESS_FILENAME_MATCHER)
end
# Read all the files in <source>/<dir>/_posts and create a new Document
# object with each one.
#
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_posts(dir)
read_publishable(dir, "_posts", Document::DATE_FILENAME_MATCHER)
end
With the referenced constants being:
DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze
As you can see, DATE_FILENAME_MATCHER as used in read_posts() requires a date ((\d{2,4}-\d{1,2}-\d{1,2})); I put date: 2021-07-06 in the frontmatter.
I couldn't really get collections to work, and this also solves another problem I had where storing binary files such as images in _drafts would error out as it tried to process them.
Arguably a bit ugly, but it works well. Downside is that it may break on update, although I've been patching various things for years and never really had any issues with it thus far. This is with Jekyll 4.2.0.
I wanted to use posts but not have the filenames in the date. The closest I got was naming the posts with an arbitrary 'date' like 0001-01-01cool-post.md and then use a different property to access the date.
If you use the last-modified-at plugin - https://github.com/gjtorikian/jekyll-last-modified-at - then you can use page.last_modified_at in your _layouts/post.html and whatever file you are running {% for post in site.posts %} in.
Now the dates are retrieved from the last git commit date (not author date) and the page.date is unused.
In the json schema for the config file are actually some useful information. See below code block for some examples.
I have set it to /:categories/:title. That drops the date and file extension, while preserving the categories.
I still use a proper date for the file name because you can use that date in your templates. I.e. to display the date on a post using {{ page.date }}.
{
"global-permalink": {
"description": "The global permalink format\nhttps://jekyllrb.com/docs/permalinks/#global",
"type": "string",
"default": "date",
"examples": [
"/:year",
"/:short_year",
"/:month",
"/:i_month",
"/:short_month",
"/:day",
"/:i_day",
"/:y_day",
"/:w_year",
"/:week",
"/:w_day",
"/:short_day",
"/:long_day",
"/:hour",
"/:minute",
"/:second",
"/:title",
"/:slug",
"/:categories",
"/:slugified_categories",
"date",
"pretty",
"ordinal",
"weekdate",
"none",
"/:categories/:year/:month/:day/:title:output_ext",
"/:categories/:year/:month/:day/:title/",
"/:categories/:year/:y_day/:title:output_ext",
"/:categories/:year/:week/:short_day/:title:output_ext",
"/:categories/:title:output_ext"
],
"pattern": "^((/(:(year|short_year|month|i_month|short_month|long_month|day|i_day|y_day|w_year|week|w_day|short_day|long_day|hour|minute|second|title|slug|categories|slugified_categories))+)+|date|pretty|ordinal|weekdate|none)$"
}
}

nginx directories without slash

I have this configuration of nginx + phpfpm + phpmyadmin:
root /var/www/utils;
location ~ ^/phpmyadmin/.*\.(jpg|jpeg|gif|png|css|js|ico)$ {
root /var/www/utils;
}
location = /phpmyadmin {
index index.php;
}
location ~ ^/phpmyadmin.*(\.php|)$ {
index index.php;
fastcgi_index index.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
All is good, but if I remove "location = /phpmyadmin", I get 403 error on _http://server/phpmyadmin.
How can I access to the ALL subdirectories such as _http://server/phpmyadmin/setup ?
I get "Access to the script '/var/www/utils/phpmyadmin/setup' has been denied - on every directory without slash at the end, if I haven't written a special config for an each one.
As stated in nginx documentation:
$fastcgi_script_name variable takes value of incoming request URI, and in case URI is finished by a slash, then $fastcgi_script_name is appended with what is defined with fastcgi_index directive.
So if your request is "/phpmyadmin/setup/" and fastcgi_index is set to "index.php", then $fastcgi_script_name variable will be "/phpmyadmin/setup/index.php". Therefore $document_root plus $fastcgi_script_name will be "/var/www/utils/phpmyadmin/setup/index.php", which should work fine.
But if you make request like "/phpmyadmin/setup" (without slash at the end), then $fastcgi_script_name will not be appended by fastcgi_index, i.e. it would be just "/phpmyadmin/setup". And $document_root plus $fastcgi_script_name will be "/var/www/utils/phpmyadmin/setup", which won't work since there is not such file.
You should either use URIs with slashes, or define a rewrite rule (in a "server" block of configuration), which will be adding slash to the URIs that do not end with some extension (so that URIs like "/phpmyadmin/myscript.php" won't transformed into "/phpmyadmin/myscript.php/".
It should be like:
rewrite ^([^\.]*[^\/])$ $1/ break;
Did not test that myself, though.

How to set config=value in php.ini with Puppet?

I'm doing my first steps in Puppet and ran into a problem. I've installed PHP on a Linux server and I want to do some slightly changes to php.ini file. I don't want to overwrite the whole ini file with one from repository, just change/create one simple config value.
I want to ensure, that the property upload_max_filesize in php.ini has the value of 10M.
How can I achieve this?
My preferred option would be to leave php.ini alone, and have puppet create a file in php's conf.d directory to override the values you want to change.
The less changes you make to php.ini, the easier it is to see what's going on when you need to merge your changes with the package providers changes when you upgrade php.ini in future.
file {'/etc/php5/conf.d/upload_limits.conf':
ensure => present,
owner => root, group => root, mode => 444,
content => "post_max_size = 10M \nupload_max_filesize = 10M \n",
}
There's basically 3 options:
Use augeas support in puppet (you'll need the ruby augeas libraries installed) like:
augeas { "php.ini":
notify => Service[httpd],
require => Package[php],
context => "/files/etc/php.ini/PHP",
changes => [
"set post_max_size 10M",
"set upload_max_filesize 10M",
];
}
You can use "augtool ls /files/etc/php.ini" to see the sections to understand how augeas is parsing the file and use that to work out the paths you need.
You can use an exec. Something like:
define set_php_var($value) {
exec { "sed -i 's/^;*[[:space:]]*$name[[:space:]]*=.*$/$name = $value/g' /etc/php.ini":
unless => "grep -xqe '$name[[:space:]]*=[[:space:]]*$value' -- /etc/php.ini",
path => "/bin:/usr/bin",
require => Package[php],
notify => Service[httpd];
}
}
set_php_var {
"post_max_size": value => '10M';
"upload_max_filesize": value => '10M';
}
Unfortunately, this solution doesn't understand the sections in php.ini, so adding a variable that's not already there would require extra effort. This will do the wrong thing if a variable appears in more than one section (but examples I'm looking at appear to have all unique variable names). This should work for a variable that's present but commented-out with a semi-colon.
Copy the original php.ini file into your puppet repository and use file with source => 'puppet:///...' or content => template(...) to replace the file entirely, as you indicated you would prefer not to do.
You could also use the file_line resource found in the stdlib module.
file_line{ 'php_upload_max_filesize':
path => '/path/to/php.ini',
line => "upload_max_filesize = 10M",
}
Since this will append the line to the file if one exactly matching it does not exist, and since the last instance of a config value takes precedence over those earlier in the file it will work. This is how I do it when i only have a couple things to change.
An alternative approach, if you're using Apache as your web server, is to set the php variable in your Apache virtualhost file (which will probably be somewhere in your Puppet manifests directory).
For example:
<VirtualHost *:80>
ServerName app.dev
DocumentRoot /srv/app/public
## etc...
php_value upload_max_filesize 10M
</VirtualHost>
This doesn't actually change php.ini, but - depending on your set-up - may be a simple way of achieving the same effect.

Using a hash sign (#) in a .htaccess search

So the jist of this is,
I have a file:
search.php
When I goto:
search.php?search=%23HashTag
The search returns: #HashTag
But when I use my .htaccess method:
/search/%23HashTag
Nothing is returned. And i've tested by putting the number sign later in the search and it returns upto that point.
This is what I have:
RewriteRule ^search/([^\.]+)$ search.php?search=$1 [NE,L]
What am I doing wrong..?
Change your flags to [NE,B,L].
http://httpd.apache.org/docs/current/rewrite/flags.html#flag_b
mod_rewrite unescapes the url before applying transformations. I'm not sure why it loses anything after the hash (maybe it re-interprets it as a url, and discards the fragment?). In any case, [B] re-escapes the url before running it through the rewrite rule.
Does replacing it with \%23 work ok?
(Clarity: Opposed to writing the # in the .htaccess file)