Forum Moderators: phranque

Message Too Old, No Replies

LONG Post: Need help with htaccess redirect in CMS

         

minarets

2:31 pm on May 31, 2014 (gmt 0)

10+ Year Member



Hello,

(Apologies in advance for the long post, the bulk of it is htaccess. Hopefully someone is patient enough to help me with this and I wanted to include all the necessary info up-front.)
I'm in desperate need of some help with creating proper 301s on a CMS/gallery site with approx 14,000 "products" indexed.

Background info:

When a new product is created on the site, 3 physical files are required:
A. A large-size image which later gets displayed on the website, in the form of:
COMPANYNAME Category - Subcategory Name - AAA123 01.jpg
B. The corresponding thumbnail in the form of:
thumb_COMPANYNAME Category - Subcategory Name - AAA123 01.jpg
C. One or more 'deliverable' files in the form of:
LicenseA_COMPANYNAME Category - Subcategory Name - AAA123 01.zip


Once published, the product
COMPANYNAME Category - Sub-Category Name - AAA123 01 (.jpg/.zip)
gets the URL:
https://www.domain.com/detail/1000-COMPANYNAME-Category-_-Sub_Category-Name-_-AAA123-01.html


There are no actual html files in the /detail/ directory.. they're generated on-the-fly with that path.
The '1000' is the product number in the database.. i.e. the 1000th product added becomes '1000-' and so on.
Spaces in the actual filename become hyphens in the URL
Hyphens in the actual filename become underscores in the URL
The filenames are not renamed in any way on the filesystem.
If I right-click an image in my browser and select "View Image Info" it shows up like this:
https://www.domain.com/gallery/Images/Category/AAA/COMPANYNAME%20Category%20-%20Sub%20Category%20Name%20-%20AAA123%2001.jpg



This is the current state of the .htaccess as installed by the CMS, with a couple mods:

# PHP 5.2
AddType application/x-httpd-php52 .php

RewriteEngine On

# block some habitual hotlinkers
RewriteCond %{HTTP_REFERER} ^http://(.+\.)?gensun\.org/ [NC,OR]
RewriteCond %{HTTP_REFERER} ^http://(.+\.)?beling\.net/ [NC]
RewriteRule .*\.(jpg|gif|bmp|png)$ [F]

<Files .htaccess>
order allow,deny
deny from all
</Files>

########## Begin - Rewrite rules to block out some common exploits
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [OR]
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Send all blocked request to homepage with 403 Forbidden error!
Options FollowSymLinks
RewriteRule ^(.*)$ index.php [F,L]
########## End - Rewrite rules to block out some common exploits

RewriteRule ^(others)(.*)(.html|htm)$ $1$2$3 [NC,L]
RewriteRule ^(help)(.htm)$ $1$2 [NC,L]
RewriteRule ^(help_menu)(.htm)$ $1$2 [NC,L]
RewriteRule ^(help_contents)(.htm)$ $1$2 [NC,L]
RewriteRule ^(installation)(.html)$ $1$2 [NC,L]
RewriteRule ^(resultC)(.html)$ $1$2 [NC,L]
RewriteRule ^(resultY)(.html)$ $1$2 [NC,L]
RewriteRule ^(secure-hosting-htmlbad)(.html)$ $1$2 [NC,L]
RewriteRule ^(secure-hosting-htmlgood)(.html)$ $1$2 [NC,L]
RewriteRule ^(secure-hosting-template)(.html)$ $1$2 [NC,L]
RewriteRule ^(wtc_service)(.htm)$ $1$2 [NC,L]
RewriteRule ^(images)(.*)(.html|htm)$ $1$2$3 [NC,L]
RewriteRule ^(logout_private)/(.*).html$ logout.php?from=private_gallery.php&mode=$2 [NC,L]
RewriteRule ^(.*[\/])(logout_private)/(.*).html$ logout.php?from=private_gallery.php&mode=$3 [NC,L]
RewriteRule ^(logout_private.html)$ logout.php?from=private_gallery.php&mode=1 [NC,L]
RewriteRule ^(cb.html)$ cb.php [NC,L]
RewriteRule ^(login.html)$ user_login.php [NC,L]
RewriteRule ^(private_gallery.html)$ private_gallery.php [NC,L]
RewriteRule ^(index|logout)/(.*)?$ $1.php?link=$2 [NC,L]
RewriteRule ^(index)$ index.php [NC,L]
RewriteRule ^(index\/+)$ index.php [NC,L]

#new seo urls

RewriteRule ^(.*[\/])logout.html$ logout.php?from=index.php [NC,L]
RewriteRule ^logout.html$ logout.php?from=index.php [NC,L]

RewriteRule ^(rss[\/])(.*)(\.html)?$ rss.php?arg=$1$2 [NC,L]
RewriteRule ^(.*[\/])(rss[\/])(.*)(\.html)?$ rss.php?arg=$1$2$3 [NC,L]

RewriteRule ^register.html$ register.php [NC,L]
RewriteRule ^(.*[\/])(register.html)$ register.php?arg=$1$2 [NC,L]

RewriteRule ^((.*)\.html)?$ index.php?arg=$1 [NC,L]

RewriteRule ^(cms[\/])(.*)?$ index.php?arg=$1$2 [NC,L]
RewriteRule ^(.*[\/])(cms[\/])(.*)?$ index.php?arg=$1$2$3 [NC,L]

RewriteRule ^(.*[\/])search[\/]?$ index.php?arg=$1search/index.html [NC,L]
RewriteRule ^(.*[\/])search?$ index.php?arg=$1search/index.html [NC,L]
RewriteRule ^search[\/]?$ index.php?arg=search/index.html [NC,L]
RewriteRule ^search?$ index.php?arg=search/index.html [NC,L]

RewriteRule ^(.*[\/])new_media[\/]?$ index.php?arg=$1new_media/index.html [NC,L]
RewriteRule ^(.*[\/])new_media?$ index.php?arg=$1new_media/index.html [NC,L]
RewriteRule ^new_media[\/]?$ index.php?arg=new_media/index.html [NC,L]
RewriteRule ^new_media?$ index.php?arg=new_media/index.html [NC,L]

RewriteRule ^(.*[\/])popular[\/]?$ index.php?arg=$1popular/index.html [NC,L]
RewriteRule ^(.*[\/])popular?$ index.php?arg=$1popular/index.html [NC,L]
RewriteRule ^popular[\/]?$ index.php?arg=popular/index.html [NC,L]
RewriteRule ^popular?$ index.php?arg=popular/index.html [NC,L]

RewriteRule ^(.*[\/])lightbox[\/]?$ index.php?arg=$1lightbox/index.html [NC,L]
RewriteRule ^(.*[\/])lightbox?$ index.php?arg=$1lightbox/index.html [NC,L]
RewriteRule ^lightbox[\/]?$ index.php?arg=lightbox/index.html [NC,L]
RewriteRule ^lightbox?$ index.php?arg=lightbox/index.html [NC,L]

RewriteRule ^(.*[\/])news[\/]?$ index.php?arg=$1news/index.html [NC,L]
RewriteRule ^(.*[\/])news?$ index.php?arg=$1news/index.html [NC,L]
RewriteRule ^news[\/]?$ index.php?arg=news/index.html [NC,L]
RewriteRule ^news?$ index.php?arg=news/index.html [NC,L]

RewriteRule ^(.*[\/])portfolio[\/]?$ index.php?arg=$1portfolio/index.html [NC,L]
RewriteRule ^(.*[\/])portfolio?$ index.php?arg=$1portfolio/index.html [NC,L]
RewriteRule ^portfolio[\/]?$ index.php?arg=portfolio/index.html [NC,L]
RewriteRule ^portfolio?$ index.php?arg=portfolio/index.html [NC,L]

RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.domain.com/$1 [R=301,L]

#RewriteRule ^(.*)\.html?$ index.php?arg=$1.html [NC,L]

ErrorDocument 400 /errors/400.shtml
ErrorDocument 401 /errors/401.shtml
ErrorDocument 403 /403.php
ErrorDocument 404 /404.php
ErrorDocument 500 /errors/500.shtml



This is what I'd like to accomplish:

1. Rename the physical files on the system:
2. Replace capitals with lowercase (more desirable for SEO)
3. Replace spaces with hyphens and " - " with single hyphen (to eliminate potential issues with character encodings incorrectly translating the spaces)
I can write a batch script to do this directly on the server so that's no problem.

4. Rename the file and URL references in the database to match the changes made in 1-3. I can do this with sql queries.

After doing steps 1-4, I'll want to modify the htaccess so search engines and other inbound links will be bounced from the old and no longer existing URL:
https://www.domain.com/detail/5637-COMPANYNAME-Category-_-Sub_Category-Name-_-AAA123-01.html

to the new cleaned URL:
https://www.domain.com/detail/5637-companyname-category-sub-category-name-AAA123-01.html

and the old image name (which google loves to go to directly):
https://www.domain.com/gallery/COMPANYNAME Category - Sub-Category Name - AAA123 01.jpg

to the new:
https://www.domain.com/gallery/companyname-category-sub-category-name-AAA123-01.jpg



These redirects, as far as I can tell, should only happen on the /gallery/ and /detail/ directories, and only *after* that part of the path instead of applied to the whole URL.

Can this htaccess be cleaned up at all and/or streamlined without breaking the existing site?
How would I need to modify it to take into account the changes outlined in Steps 1 and 2 above? I hope someone can help with this. Again, sorry for the very long post and thank you sincerely for reading this far!

lucy24

5:56 pm on May 31, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



https://www.domain.com/detail/5637-COMPANYNAME-Category-_-Sub_Category-Name-_-AAA123-01.html

Do the URLs in question always fit exactly this pattern, with exactly this many hyphens and lowlines (and does a single - in the original turn into -_- or does the original filename really have a space on either side of the hyphen?)* If everything fits around exactly the same pattern-- or at most 3 or 4 variations-- it's straightforward. Otherwise it becomes so messy and complicated that you really should detour to a quick php script to do everything at once. You will then need a supplementary [L] rule to protect requests for fixup.php (or whatever you choose to call it) to prevent the CMS from messing with it.

Do you know any php at all? For comparison purposes: It would be wildly irresponsible of me to even suggest the fixup code-- but I'm confident I could make something up myself, although I only speak three words of php.


* Horrendously common punctuation error that makes me foam at the mouth. You never space around a hyphen. If you mean dash, use a dash. (ASCII representation is -- two hyphens.) Some languages space around dashes; some don't.

minarets

1:17 am on Jun 1, 2014 (gmt 0)

10+ Year Member



Hi Lucy,

Thanks for the reply. I'm away from my local copy of the site until tomorrow afternoon, but I'll look at the total number of variations as soon as I can and reply here again, but I think there are just a handful of variations.

To answer your other question, the original filenames *do* have SPACEdashSPACE in the names.. When the CMS gets hold of them, any existing dashes becomes underlines, and any existing spaces become dashes.. This presents a problem because in order to have the URL with dashes, the image name from which the URL is created must have spaces. If the image name has dashes, the URL gets created with underlines. It's ridiculous but I don't recall a way to have both.. Either the image name or the URL name must be suboptimal.

Oh, and your last question.. I know very little php.

Again, thanks for the reply and I'll post a hopefully thorough accounting of the total variations as soon as I can tomorrow.

lucy24

1:27 am on Jun 1, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Either the image name or the URL name must be suboptimal.

Given the choice, go with the better page URL. Images are subsidiary.

_-_ is not attractive by any measure.

minarets

11:16 pm on Jun 1, 2014 (gmt 0)

10+ Year Member



Ugh, ok, there are quite a bit more variations than I suspected at first, and it seems the URLs are not being created from the image filename, but from the embedded IPTC metatag inside the image. One problem is that not all of the site content has been loaded yet, so there may be as-yet-unseen variations.

One benefit is that the IPTC metatags could potentially be reworked to remove all dashes and SPACEdashSPACE instances, then the database modified directly to reflect those changes, which would then mean just a straight redirect of old messy name to new clean name.

I'm thinking the PHP method may be better as long as it doesn't bog down the server. Is the PHP method something that can be configured for each URL or URL variation i.e. a separate PHP "301 handler script" for each variation type, or maybe a separate PHP 301 handler script for each letter of the alphabet, or Category? I think that way I could make these changes progressively, starting on a small category as a test to make sure it works properly, instead of changing 14000 JPG names and 14000 corresponding thumbnail names and 14000 URLs all in one shot and then discovering it isn't working and having to backtrack.. That would be a nightmare.

In any case, these are (I'm pretty sure) the total variations "currently" listed on the site:

COMPANYNAME Imagepack - Word Word AB123.jpg
thumb_COMPANYNAME Imagepack - Word Word AB123.jpg
COMPANYNAME Imagepack - Word Word ABC123.jpg
thumb_COMPANYNAME Imagepack - Word Word ABC123.jpg
COMPANYNAME Imagepack - Word Word AbCd123.jpg
thumb_COMPANYNAME Imagepack - Word Word AbCd123.jpg
COMPANYNAME Imagepack - Word Word Word ABC123.jpg
thumb_COMPANYNAME Imagepack - Word Word Word ABC123.jpg
COMPANYNAME Imagepack - Word Word Word ABC123.4.jpg
thumb_COMPANYNAME Imagepack - Word Word Word ABC123.4.jpg
COMPANYNAME Imagepack - Word Word word Word ABC123.jpg
thumb_COMPANYNAME Imagepack - Word Word word Word ABC123.jpg
COMPANYNAME Imagepack - Word Word Word Word ABC123.jpg
thumb_COMPANYNAME Imagepack - Word Word Word Word ABC123.jpg
COMPANYNAME Imagepack - Word Word Word Word ABCD12.jpg
thumb_COMPANYNAME Imagepack - Word Word Word Word ABCD12.jpg
COMPANYNAME Imagepack - Word Word Word Word ABCD123.jpg
thumb_COMPANYNAME Imagepack - Word Word Word Word ABCD123.jpg
COMPANYNAME Imagepack - Word Word Word Word ABCD12.3.jpg
thumb_COMPANYNAME Imagepack - Word Word Word Word ABCD12.3.jpg
COMPANYNAME Imagepack - Word Word Word word Word ABCD12.jpg
thumb_COMPANYNAME Imagepack - Word Word Word word Word ABCD12.jpg

COMPANYNAME Category - Word - AB123 01.jpg
thumb_COMPANYNAME Category - Word - AB123 01.jpg
COMPANYNAME Category - Word - AbCd123 01.jpg
thumb_COMPANYNAME Category - Word - AbCd123 01.jpg
COMPANYNAME Category - Word - ABC123 01.jpg
thumb_COMPANYNAME Category - Word - ABC123 01.jpg
COMPANYNAME Category - Word - ABC123 01 Word.jpg
thumb_COMPANYNAME Category - Word - ABC123 01 Word.jpg
COMPANYNAME Category - Word - ABC123 01 Word Word.jpg
thumb_COMPANYNAME Category - Word - ABC123 01 Word Word.jpg
COMPANYNAME Category - Word - ABC123 01 Word Word 02 Word.jpg
thumb_COMPANYNAME Category - Word - ABC123 01 Word Word 02 Word.jpg
COMPANYNAME Category - Word Word - ABC123 01.jpg
thumb_COMPANYNAME Category - Word Word - ABC123 01.jpg
COMPANYNAME Category - Word Word - ABC123 01 word.jpg
thumb_COMPANYNAME Category - Word Word - ABC123 01 word.jpg
COMPANYNAME Category - Word Word - ABC123 01 word word.jpg
thumb_COMPANYNAME Category - Word Word - ABC123 01 word word.jpg
COMPANYNAME Category - Word Word - ABC123.4 01.jpg
thumb_COMPANYNAME Category - Word Word - ABC123.4 01.jpg
COMPANYNAME Category - Word word Word - ABC123 01.jpg
thumb_COMPANYNAME Category - Word word Word - ABC123 01.jpg
COMPANYNAME Category - Word Word Word - ABC123 01.jpg
thumb_COMPANYNAME Category - Word Word Word - ABC123 01.jpg
COMPANYNAME Category - Word Word Word - ABCD123 01.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD123 01.jpg
COMPANYNAME Category - Word Word Word - ABCD12.3 01.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD12.3 01.jpg
COMPANYNAME Category - Word Word Word - ABCD12.3 01 Word.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD12.3 01 Word.jpg
COMPANYNAME Category - Word Word Word - ABCD12 01 Word.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD12 01 Word.jpg
COMPANYNAME Category - Word Word Word - ABCD12 01 Word 02.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD12 01 Word 02.jpg
COMPANYNAME Category - Word Word Word - ABCD12 01 Word Word.jpg
thumb_COMPANYNAME Category - Word Word Word - ABCD12 01 Word Word.jpg

What a mess!

minarets

11:20 pm on Jun 1, 2014 (gmt 0)

10+ Year Member



(I should have wrapped that in code tags to keep the indents straight.. Basically, every line that starts with 'thumb_' is exactly the same as the line above it, except it has the thumbnail prefix on it.)

minarets

11:53 pm on Jun 1, 2014 (gmt 0)

10+ Year Member



Actually.. hmm.. now that I've had a chance to step away from it for a moment.. the URLs in question are in 2 forms..

site.com/detail/12345-COMPANYNAME-Imagepack-_-Word-Word-Word-ABC123.html
and
site.com/detail/12346-COMPANYNAME-Category-_-Word-Word-_-ABC123-01.html

So it's really just the single instance of -_- when it's a "pack" of images, and the two instance when it's an individual image.. The amount of content inbetween those instances shouldn't matter.. It becomes

somecontent-_-somemorecontent.html
and
somecontent-_-somemorecontent-_-alittlemorecontent.html

As for the image files, I'm looking for definite patterns in those also, but I have to search in the embedded metatags and not the actual filenames.. will update on that as soon as I can.

lucy24

12:46 am on Jun 2, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



The php method goes like this:

RewriteRule [_-] /fixup.php [L]


You don't need to pass any argument to the php, because it will still remember the requested URI. Err... I think it does. I did say I don't speak php, didn't I?

Although superficially a rewrite, it should be located among the external redirects in htaccess. The php file itself simply performs a global replace of hyphens, spaces, lowlines etc as needed, and also globally changes everything to lower-case. It then issues a 301 redirect, giving the newly cleaned-up name as target. I would count this as an extremely low-maintenance request, probably about four lines of php. The php page itself never actually gets sent out; it's just there to do the work.

site.com/detail/12345-COMPANYNAME-Imagepack-_-Word-Word-Word-ABC123.html
and
site.com/detail/12346-COMPANYNAME-Category-_-Word-Word-_-ABC123-01.html

Is it literally always exactly these two patterns?
/detail/\d{5}-COMPANYNAME-\w{2,}-_-\w{2,}-\w{2,}-\w{2,}-\w{2,}\.html
and
/detail/\d{5}-COMPANYNAME-\w{2,}-_-\w{2,}-\w{2,}-_-\w{2,}-\d{2}\.html

?
I said {2,} instead of + because a lowline _ counts as \w ("word" character). If it's really just those two patterns, it can easily be done in htaccess.

minarets

11:04 am on Jun 3, 2014 (gmt 0)

10+ Year Member



Not literally just those two patterns.. I'll break down the first example into sections:

site.com/detail/ <- always the same
12345 <- integer starting at 1, up to X (every new item added gets the next number)
-COMPANYNAME- <- always there, should perhaps remain allcaps
Imagepack <- always there, could be made lowercase
-_- <- always there, should be changed to a single dash
Word-Word-Word <- always there but a variable number of words. Could be Word, could be Word-Word, could be Word-Word-Word, could be Word-Word-Word-Word, etc, and could be mixed case, i.e. Word-word-Word
- <- always there
ABC123 <- X number of capital letters and X number of numbers
Most end here with .html but there are some which have a decimal or further mixed case alphanumeric variations.

The one *real* constant in this format is:
integer(s)-COMPANYNAME-Imagepack-_-more mixed case content on the right side.html

and for the second format:
integer(s)-COMPANYNAME-Category-_-more mixed case content-_-more mixed case content.html

If it needs to be separated down to the exact number of words and dashes and capitals and lowercase then there may just be too many variations.

Let me ask you this.. You said above that it's "superficially a rewrite" rather than redirect.. Does this mean that the database side of things doesn't have to be changed? In other words, if I were doing a *redirect* from an old page to a new page, that new page would have to actually exist, right? And since the pages are generated dynamically, that means the necessary changes would need to be made in the database first in order for the dynamic page to be created with the new name. But if this is a "rewrite" as you said then theoretically there shouldn't be any changes required to the database since just the URL is being rewritten but the actual page "behind the scenes" remains the same as it was?

lucy24

5:45 pm on Jun 3, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Word-Word-Word <- always there but a variable number of words.

That's bad news, because each hyphen needs to be handled individually. In theory it could all be done in htaccess using the [N] flag, but frankly I wouldn't try it unless your name is JDMorgan (onetime moderator of this subforum).

You said above that it's "superficially a rewrite" rather than redirect.. Does this mean that the database side of things doesn't have to be changed?

Within htaccess it looks like a rewrite, because the rule has only the [L] flag. The php page that you're rewriting to will then do any lookups-- or just execute global replaces, probably in plain text without resorting to Regular Expressions-- and will wind up by issuing a 301 redirect. So it's functionally a redirect, even though Apache thinks it's "only" a rewrite.

Naming of the underlying image files is really a separate issue. It's entirely up to you whether you'll use filenames directly derived from the page URLs, or whether instead you want to rewrite to some other form. Here too you can use a quick php script to do the rewriting, only this time you needn't bother about an external redirect (because the image files have no visible existence to the world at large, right?).

Capitalizing or lowercasing is trivial in Apache if and only if it's your own server, because you can then use the built-in RewriteMap. You can't do this in htaccess. Theoretically you can, but only if the map was declared in the config file. Normally on shared hosting they wouldn't even install it.

minarets

10:33 pm on Jun 3, 2014 (gmt 0)

10+ Year Member



I'm starting to think there isn't a solution. It looks like continuing along the same path may be the only way, and maybe look for a different stock imagery cms that can create 301s internally into which we could migrate all the images.

What if we just wanted to get rid of the instances of -_- and replace them with single hyphens, leaving alone the uppercase to lowercase conversion and everything else? Does that look possible? There are only two variations of that: URLs which have one instance of -_- and URLs which have two instances of -_-

only this time you needn't bother about an external redirect (because the image files have no visible existence to the world at large, right?).

Well, not exactly. The images are displayed on the pages we're attempting to rename. Here's how it works:
A photo is imported into the system. That photo has embedded IPTC/XMP metatags. If the embedded IPTC:Subject is:

COMPANYNAME Landscapes - Terrains Dry Lakebed - TDL001

Then the system uses that IPTC metadata to create the URL on which that image is displayed:

/detail/1247-COMPANYNAME-Landscapes-_-Terrains-Dry-Lakebed-_-TDL001.html

So if you go to that URL, you'll see the image whose IPTC metadata was used to create that URL.

lucy24

12:17 am on Jun 4, 2014 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



URLs which have one instance of -_- and URLs which have two instances of -_-

That part's straightforward:

RewriteRule ^([^_]+)-_-([^_]+)-_-([^_]+)-_-([^_]+)$ http://www.example.com/$1-$2-$3-$4 [R=301,L]

RewriteRule ^([^_]+)-_-([^_]+)-_-([^_]+)$ http://www.example.com/$1-$2-$3 [R=301,L]

RewriteRule ^([^_]+)-_-([^_]+)$ http://www.example.com/$1-$2 [R=301,L]

et cetera for some reasonable number of -_- packages, from most to fewest.

You then end up with two kinds of hyphens: the ones that began life as spaces, and the ones that started out as hyphens surrounded by _ or space. It sounds as if that's acceptable.

btw, what I know about SEO would fit neatly into a small thimble ... but the TitleCase vs. lowercase alternation is so far down the list of possible factors that it's really not worth bothering about. Casing is really only an issue when you've got a lot of type-ins, and/or links routed via someone else's CMS, that result in things being wrongly cased through no fault of your own.